Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * This file contains backup and restore output renderers
19
 *
20
 * @package   core_backup
21
 * @copyright 2010 Sam Hemelryk
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
1441 ariadna 25
use core_course\output\activity_icon;
26
use core\output\local\properties\iconsize;
27
 
1 efrain 28
defined('MOODLE_INTERNAL') || die;
29
 
30
global $CFG;
31
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
32
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
33
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
34
 
35
/**
36
 * The primary renderer for the backup.
37
 *
38
 * Can be retrieved with the following code:
39
 * <?php
40
 * $renderer = $PAGE->get_renderer('core', 'backup');
41
 * ?>
42
 *
43
 * @package   core_backup
44
 * @copyright 2010 Sam Hemelryk
45
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46
 */
47
class core_backup_renderer extends plugin_renderer_base {
48
 
49
    /**
50
     * Same site notification display.
51
     *
52
     * @var string
53
     */
54
    private $samesitenotification = '';
55
 
56
    /**
57
     * Renderers a progress bar for the backup or restore given the items that make it up.
58
     *
59
     * @param array $items An array of items
60
     * @return string
61
     */
62
    public function progress_bar(array $items) {
63
        foreach ($items as &$item) {
64
            $text = $item['text'];
65
            unset($item['text']);
66
            if (array_key_exists('link', $item)) {
67
                $link = $item['link'];
68
                unset($item['link']);
69
                $item = html_writer::link($link, $text, $item);
70
            } else {
71
                $item = html_writer::tag('span', $text, $item);
72
            }
73
        }
74
        return html_writer::tag('div', join(get_separator(), $items), array('class' => 'backup_progress clearfix'));
75
    }
76
 
77
    /**
78
     * The backup and restore pages may display a log (if any) in a scrolling box.
79
     *
80
     * @param string $loghtml Log content in HTML format
81
     * @return string HTML content that shows the log
82
     */
83
    public function log_display($loghtml) {
84
        $out = html_writer::start_div('backup_log');
85
        $out .= $this->output->heading(get_string('backuplog', 'backup'));
86
        $out .= html_writer::start_div('backup_log_contents');
87
        $out .= $loghtml;
88
        $out .= html_writer::end_div();
89
        $out .= html_writer::end_div();
90
        return $out;
91
    }
92
 
93
    /**
94
     * Set the same site backup notification.
95
     *
96
     */
97
    public function set_samesite_notification() {
98
        $this->samesitenotification = $this->output->notification(get_string('samesitenotification', 'backup'), 'info');
99
    }
100
 
101
    /**
102
     * Get the same site backup notification.
103
     *
104
     */
105
    public function get_samesite_notification() {
106
        return $this->samesitenotification;
107
    }
108
 
109
    /**
110
     * Prints a dependency notification
111
     *
112
     * @param string $message
113
     * @return string
114
     */
115
    public function dependency_notification($message) {
116
        return html_writer::tag('div', $message, array('class' => 'notification dependencies_enforced'));
117
    }
118
 
119
    /**
120
     * Displays the details of a backup file
121
     *
122
     * @param stdClass $details
123
     * @param moodle_url $nextstageurl
124
     * @return string
125
     */
126
    public function backup_details($details, $nextstageurl) {
127
        $yestick = $this->output->pix_icon('i/valid', get_string('yes'));
128
        $notick = $this->output->pix_icon('i/invalid', get_string('no'));
129
 
130
        $html  = html_writer::start_tag('div', array('class' => 'backup-restore'));
131
 
132
        $html .= html_writer::start_tag('div', ['class' => 'backup-section',
133
            'role' => 'table', 'aria-labelledby' => 'backupdetailsheader']);
134
        $html .= $this->output->heading(get_string('backupdetails', 'backup'), 2, 'header', 'backupdetailsheader');
135
        $html .= $this->backup_detail_pair(get_string('backuptype', 'backup'), get_string('backuptype'.$details->type, 'backup'));
136
        $html .= $this->backup_detail_pair(get_string('backupformat', 'backup'), get_string('backupformat'.$details->format, 'backup'));
137
        $html .= $this->backup_detail_pair(get_string('backupmode', 'backup'), get_string('backupmode'.$details->mode, 'backup'));
138
        $html .= $this->backup_detail_pair(get_string('backupdate', 'backup'), userdate($details->backup_date));
139
        $html .= $this->backup_detail_pair(get_string('moodleversion', 'backup'),
11 efrain 140
                html_writer::tag('span', s($details->moodle_release), array('class' => 'moodle_release')).
141
                html_writer::tag('span', '[' . s($details->moodle_version) .']', array('class' => 'moodle_version sub-detail')));
1 efrain 142
        $html .= $this->backup_detail_pair(get_string('backupversion', 'backup'),
11 efrain 143
                html_writer::tag('span', s($details->backup_release), array('class' => 'moodle_release')).
144
                html_writer::tag('span', '[' . s($details->backup_version) . ']', array('class' => 'moodle_version sub-detail')));
1 efrain 145
        $html .= $this->backup_detail_pair(get_string('originalwwwroot', 'backup'),
11 efrain 146
                html_writer::tag('span', s($details->original_wwwroot), array('class' => 'originalwwwroot')).
147
                html_writer::tag('span', '[' . s($details->original_site_identifier_hash) . ']', array('class' => 'sitehash sub-detail')));
1 efrain 148
        if (!empty($details->include_file_references_to_external_content)) {
149
            $message = '';
150
            if (backup_general_helper::backup_is_samesite($details)) {
151
                $message = $yestick . ' ' . get_string('filereferencessamesite', 'backup');
152
            } else {
153
                $message = $notick . ' ' . get_string('filereferencesnotsamesite', 'backup');
154
            }
155
            $html .= $this->backup_detail_pair(get_string('includefilereferences', 'backup'), $message);
156
        }
157
 
158
        $html .= html_writer::end_tag('div');
159
 
160
        $html .= html_writer::start_tag('div', ['class' => 'backup-section settings-section',
161
            'role' => 'table', 'aria-labelledby' => 'backupsettingsheader']);
162
        $html .= $this->output->heading(get_string('backupsettings', 'backup'), 2, 'header', 'backupsettingsheader');
163
        foreach ($details->root_settings as $label => $value) {
164
            if ($label == 'filename' or $label == 'user_files') {
165
                continue;
166
            }
167
            $html .= $this->backup_detail_pair(get_string('rootsetting'.str_replace('_', '', $label), 'backup'), $value ? $yestick : $notick);
168
        }
169
        $html .= html_writer::end_tag('div');
170
 
171
        if ($details->type === 'course') {
172
            $html .= html_writer::start_tag('div', ['class' => 'backup-section',
173
                    'role' => 'table', 'aria-labelledby' => 'backupcoursedetailsheader']);
174
            $html .= $this->output->heading(get_string('backupcoursedetails', 'backup'), 2, 'header', 'backupcoursedetailsheader');
11 efrain 175
            $html .= $this->backup_detail_pair(get_string('coursetitle', 'backup'), format_string($details->course->title));
176
            $html .= $this->backup_detail_pair(get_string('courseid', 'backup'), clean_param($details->course->courseid, PARAM_INT));
1 efrain 177
 
178
            // Warning users about front page backups.
179
            if ($details->original_course_format === 'site') {
180
                $html .= $this->backup_detail_pair(get_string('type_format', 'plugin'), get_string('sitecourseformatwarning', 'backup'));
181
            }
182
            $html .= html_writer::start_tag('div', array('class' => 'backup-sub-section'));
183
            $html .= $this->output->heading(get_string('backupcoursesections', 'backup'), 3, array('class' => 'subheader'));
184
            foreach ($details->sections as $key => $section) {
185
                $included = $key.'_included';
186
                $userinfo = $key.'_userinfo';
187
                if ($section->settings[$included] && $section->settings[$userinfo]) {
188
                    $value = get_string('sectionincanduser', 'backup');
189
                } else if ($section->settings[$included]) {
190
                    $value = get_string('sectioninc', 'backup');
191
                } else {
192
                    continue;
193
                }
11 efrain 194
                $html .= $this->backup_detail_pair(get_string('backupcoursesection', 'backup', format_string($section->title)), $value);
1 efrain 195
                $table = null;
196
                foreach ($details->activities as $activitykey => $activity) {
197
                    if ($activity->sectionid != $section->sectionid) {
198
                        continue;
199
                    }
200
                    if (empty($table)) {
201
                        $table = new html_table();
202
                        $table->head = array(get_string('module', 'backup'), get_string('title', 'backup'), get_string('userinfo', 'backup'));
203
                        $table->colclasses = array('modulename', 'moduletitle', 'userinfoincluded');
204
                        $table->align = array('left', 'left', 'center');
205
                        $table->attributes = array('class' => 'activitytable generaltable');
206
                        $table->data = array();
207
                    }
208
                    $name = get_string('pluginname', $activity->modulename);
1441 ariadna 209
                    $icon = activity_icon::from_modname($activity->modulename)
210
                        ->set_icon_size(iconsize::SIZE4)
211
                        ->set_colourize(false);
212
 
213
                    $content = $this->output->container(
214
                        contents: $this->output->render($icon) . $name,
215
                        classes: 'd-flex align-items-center',
216
                    );
217
 
218
                    $table->data[] = [
219
                        $content,
11 efrain 220
                        format_string($activity->title),
1 efrain 221
                        ($activity->settings[$activitykey.'_userinfo']) ? $yestick : $notick,
1441 ariadna 222
                    ];
1 efrain 223
                }
224
                if (!empty($table)) {
225
                    $html .= $this->backup_detail_pair(get_string('sectionactivities', 'backup'), html_writer::table($table));
226
                }
227
 
228
            }
229
            $html .= html_writer::end_tag('div');
230
            $html .= html_writer::end_tag('div');
231
        }
232
 
233
        $html .= $this->continue_button($nextstageurl, 'post');
234
        $html .= html_writer::end_tag('div');
235
 
236
        return $html;
237
    }
238
 
239
    /**
240
     * Displays the general information about a backup file with non-standard format
241
     *
242
     * @param moodle_url $nextstageurl URL to send user to
243
     * @param array $details basic info about the file (format, type)
244
     * @return string HTML code to display
245
     */
246
    public function backup_details_nonstandard($nextstageurl, array $details) {
247
 
248
        $html  = html_writer::start_tag('div', array('class' => 'backup-restore nonstandardformat'));
249
        $html .= html_writer::start_tag('div', array('class' => 'backup-section'));
250
        $html .= $this->output->heading(get_string('backupdetails', 'backup'), 2, 'header');
251
        $html .= $this->output->box(get_string('backupdetailsnonstandardinfo', 'backup'), 'noticebox');
252
        $html .= $this->backup_detail_pair(
253
            get_string('backupformat', 'backup'),
254
            get_string('backupformat'.$details['format'], 'backup'));
255
        $html .= $this->backup_detail_pair(
256
            get_string('backuptype', 'backup'),
257
            get_string('backuptype'.$details['type'], 'backup'));
258
        $html .= html_writer::end_tag('div');
259
        $html .= $this->continue_button($nextstageurl, 'post');
260
        $html .= html_writer::end_tag('div');
261
 
262
        return $html;
263
    }
264
 
265
    /**
266
     * Displays the general information about a backup file with unknown format
267
     *
268
     * @param moodle_url $nextstageurl URL to send user to
269
     * @return string HTML code to display
270
     */
271
    public function backup_details_unknown(moodle_url $nextstageurl) {
272
 
273
        $html  = html_writer::start_div('unknownformat');
274
        $html .= $this->output->heading(get_string('errorinvalidformat', 'backup'), 2);
275
        $html .= $this->output->notification(get_string('errorinvalidformatinfo', 'backup'), 'notifyproblem');
276
        $html .= $this->continue_button($nextstageurl, 'post');
277
        $html .= html_writer::end_div();
278
 
279
        return $html;
280
    }
281
 
282
    /**
283
     * Displays a course selector for restore
284
     *
285
     * @param moodle_url $nextstageurl
286
     * @param bool $wholecourse true if we are restoring whole course (as with backup::TYPE_1COURSE), false otherwise
287
     * @param restore_category_search $categories
288
     * @param restore_course_search $courses
289
     * @param int $currentcourse
290
     * @return string
291
     */
1441 ariadna 292
    public function course_selector(moodle_url $nextstageurl, $wholecourse = true, ?restore_category_search $categories = null,
293
                                    ?restore_course_search $courses = null, $currentcourse = null) {
1 efrain 294
        global $CFG;
295
        require_once($CFG->dirroot.'/course/lib.php');
296
 
297
        // These variables are used to check if the form using this function was submitted.
298
        $target = optional_param('target', false, PARAM_INT);
299
        $targetid = optional_param('targetid', null, PARAM_INT);
300
 
301
        // Check if they submitted the form but did not provide all the data we need.
302
        $missingdata = false;
303
        if ($target and is_null($targetid)) {
304
            $missingdata = true;
305
        }
306
 
307
        $nextstageurl->param('sesskey', sesskey());
308
 
309
        $form = html_writer::start_tag('form', array('method' => 'post', 'action' => $nextstageurl->out_omit_querystring(),
310
            'class' => 'mform'));
311
        foreach ($nextstageurl->params() as $key => $value) {
312
            $form .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $key, 'value' => $value));
313
        }
314
 
315
        $hasrestoreoption = false;
316
 
317
        $html  = html_writer::start_tag('div', array('class' => 'backup-course-selector backup-restore'));
318
        if ($wholecourse && !empty($categories) && ($categories->get_count() > 0 || $categories->get_search())) {
319
            // New course.
320
            $hasrestoreoption = true;
321
            $html .= $form;
322
            $html .= html_writer::start_tag('div', array('class' => 'bcs-new-course backup-section'));
323
            $html .= $this->output->heading(get_string('restoretonewcourse', 'backup'), 2, array('class' => 'header'));
324
            $html .= $this->backup_detail_input(get_string('restoretonewcourse', 'backup'), 'radio', 'target',
325
                backup::TARGET_NEW_COURSE, array('checked' => 'checked'));
326
            $selectacategoryhtml = $this->backup_detail_pair(get_string('selectacategory', 'backup'), $this->render($categories));
327
            // Display the category selection as required if the form was submitted but this data was not supplied.
328
            if ($missingdata && $target == backup::TARGET_NEW_COURSE) {
329
                $html .= html_writer::span(get_string('required'), 'error');
330
                $html .= html_writer::start_tag('fieldset', array('class' => 'error'));
331
                $html .= $selectacategoryhtml;
332
                $html .= html_writer::end_tag('fieldset');
333
            } else {
334
                $html .= $selectacategoryhtml;
335
            }
336
            $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary');
337
            $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs));
338
            $html .= html_writer::end_tag('div');
339
            $html .= html_writer::end_tag('form');
340
        }
341
 
342
        if ($wholecourse && !empty($currentcourse)) {
343
            // Current course.
344
            $hasrestoreoption = true;
345
            $html .= $form;
346
            $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'targetid', 'value' => $currentcourse));
347
            $html .= html_writer::start_tag('div', array('class' => 'bcs-current-course backup-section'));
348
            $html .= $this->output->heading(get_string('restoretocurrentcourse', 'backup'), 2, array('class' => 'header'));
349
            $html .= $this->backup_detail_input(get_string('restoretocurrentcourseadding', 'backup'), 'radio', 'target',
350
                backup::TARGET_CURRENT_ADDING, array('checked' => 'checked'));
351
            $html .= $this->backup_detail_input(get_string('restoretocurrentcoursedeleting', 'backup'), 'radio', 'target',
352
                backup::TARGET_CURRENT_DELETING);
353
            $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary');
354
            $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs));
355
            $html .= html_writer::end_tag('div');
356
            $html .= html_writer::end_tag('form');
357
        }
358
 
359
        // If we are restoring an activity, then include the current course.
360
        if (!$wholecourse) {
361
            $courses->invalidate_results(); // Clean list of courses.
362
            $courses->set_include_currentcourse();
363
        }
364
        if (!empty($courses) && ($courses->get_count() > 0 || $courses->get_search())) {
365
            // Existing course.
366
            $hasrestoreoption = true;
367
            $html .= $form;
368
            $html .= html_writer::start_tag('div', array('class' => 'bcs-existing-course backup-section'));
369
            $html .= $this->output->heading(get_string('restoretoexistingcourse', 'backup'), 2, array('class' => 'header'));
370
            if ($wholecourse) {
371
                $html .= $this->backup_detail_input(get_string('restoretoexistingcourseadding', 'backup'), 'radio', 'target',
372
                    backup::TARGET_EXISTING_ADDING, array('checked' => 'checked'));
373
                $html .= $this->backup_detail_input(get_string('restoretoexistingcoursedeleting', 'backup'), 'radio', 'target',
374
                    backup::TARGET_EXISTING_DELETING);
375
            } else {
376
                $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'target', 'value' => backup::TARGET_EXISTING_ADDING));
377
            }
378
            $selectacoursehtml = $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
379
            // Display the course selection as required if the form was submitted but this data was not supplied.
380
            if ($missingdata && $target == backup::TARGET_EXISTING_ADDING) {
381
                $html .= html_writer::span(get_string('required'), 'error');
382
                $html .= html_writer::start_tag('fieldset', array('class' => 'error'));
383
                $html .= $selectacoursehtml;
384
                $html .= html_writer::end_tag('fieldset');
385
            } else {
386
                $html .= $selectacoursehtml;
387
            }
388
            $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary');
389
            $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs));
390
            $html .= html_writer::end_tag('div');
391
            $html .= html_writer::end_tag('form');
392
        }
393
 
394
        if (!$hasrestoreoption) {
395
            echo $this->output->notification(get_string('norestoreoptions', 'backup'));
396
        }
397
 
398
        $html .= html_writer::end_tag('div');
399
        return $html;
400
    }
401
 
402
    /**
403
     * Displays the import course selector
404
     *
405
     * @param moodle_url $nextstageurl
406
     * @param import_course_search $courses
407
     * @return string
408
     */
1441 ariadna 409
    public function import_course_selector(moodle_url $nextstageurl, ?import_course_search $courses = null) {
1 efrain 410
        $html  = html_writer::start_tag('div', array('class' => 'import-course-selector backup-restore'));
411
        $html .= html_writer::start_tag('form', array('method' => 'post', 'action' => $nextstageurl->out_omit_querystring()));
412
        foreach ($nextstageurl->params() as $key => $value) {
413
            $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $key, 'value' => $value));
414
        }
415
        // We only allow import adding for now. Enforce it here.
416
        $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'target', 'value' => backup::TARGET_CURRENT_ADDING));
417
        $html .= html_writer::start_tag('div', array('class' => 'ics-existing-course backup-section'));
418
        $html .= $this->output->heading(get_string('importdatafrom'), 2, array('class' => 'header'));
419
        $html .= $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
420
        $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary');
421
        $html .= html_writer::start_tag('div', array('class' => 'mt-3'));
422
        $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs));
423
        $html .= html_writer::end_tag('div');
424
        $html .= html_writer::end_tag('div');
425
        $html .= html_writer::end_tag('form');
426
        $html .= html_writer::end_tag('div');
427
        return $html;
428
    }
429
 
430
    /**
431
     * Creates a detailed pairing (key + value)
432
     *
433
     * @staticvar int $count
434
     * @param string $label
435
     * @param string $value
436
     * @return string
437
     */
438
    protected function backup_detail_pair($label, $value) {
439
        static $count = 0;
440
        $count ++;
441
        $html  = html_writer::start_tag('div', ['class' => 'detail-pair', 'role' => 'row']);
442
        $html .= html_writer::tag('div', $label, ['class' => 'detail-pair-label mb-2', 'role' => 'cell']);
1441 ariadna 443
        $html .= html_writer::tag('div', $value, ['class' => 'detail-pair-value ps-2', 'role' => 'cell']);
1 efrain 444
        $html .= html_writer::end_tag('div');
445
        return $html;
446
    }
447
 
448
    /**
449
     * Creates a unique id string by appending an incremental number to the prefix.
450
     *
451
     * @param string $prefix To be used as the left part of the id string.
452
     * @return string
453
     */
454
    protected function make_unique_id(string $prefix): string {
455
        static $count = 0;
456
 
457
        return $prefix . '-' . $count++;
458
    }
459
 
460
    /**
461
     * Created a detailed pairing with an input
462
     *
463
     * @param string $label
464
     * @param string $type
465
     * @param string $name
466
     * @param string $value
467
     * @param array $attributes
468
     * @param string|null $description
469
     * @return string
470
     */
471
    protected function backup_detail_input($label, $type, $name, $value, array $attributes = array(), $description = null) {
472
        if (!empty($description)) {
473
            $description = html_writer::tag('span', $description, array('class' => 'description'));
474
        } else {
475
            $description = '';
476
        }
477
        $id = $this->make_unique_id('detail-pair-value');
478
        return $this->backup_detail_pair(
479
            html_writer::label($label, $id),
480
            html_writer::empty_tag('input', $attributes + ['id' => $id, 'name' => $name, 'type' => $type, 'value' => $value]) .
481
                $description
482
        );
483
    }
484
 
485
    /**
486
     * Creates a detailed pairing with a select
487
     *
488
     * @param string $label
489
     * @param string $name
490
     * @param array $options
491
     * @param string $selected
492
     * @param bool $nothing
493
     * @param array $attributes
494
     * @param string|null $description
495
     * @return string
496
     */
497
    protected function backup_detail_select($label, $name, $options, $selected = '', $nothing = false, array $attributes = array(), $description = null) {
498
        if (!empty ($description)) {
499
            $description = html_writer::tag('span', $description, array('class' => 'description'));
500
        } else {
501
            $description = '';
502
        }
503
        return $this->backup_detail_pair($label, html_writer::select($options, $name, $selected, false, $attributes).$description);
504
    }
505
 
506
    /**
507
     * Displays precheck notices
508
     *
509
     * @param array $results
510
     * @return string
511
     */
512
    public function precheck_notices($results) {
513
        $output = html_writer::start_tag('div', array('class' => 'restore-precheck-notices'));
514
        if (array_key_exists('errors', $results)) {
515
            foreach ($results['errors'] as $error) {
516
                $output .= $this->output->notification($error);
517
            }
518
        }
519
        if (array_key_exists('warnings', $results)) {
520
            foreach ($results['warnings'] as $warning) {
521
                $output .= $this->output->notification($warning, 'notifyproblem');
522
            }
523
        }
524
        return $output.html_writer::end_tag('div');
525
    }
526
 
527
    /**
528
     * Displays substage buttons
529
     *
530
     * @param bool $haserrors
531
     * @return string
532
     */
533
    public function substage_buttons($haserrors) {
534
        $output  = html_writer::start_tag('div', array('continuebutton'));
535
        if (!$haserrors) {
1441 ariadna 536
            $attrs = ['type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary me-1'];
1 efrain 537
            $output .= html_writer::empty_tag('input', $attrs);
538
        }
539
        $attrs = array('type' => 'submit', 'name' => 'cancel', 'value' => get_string('cancel'), 'class' => 'btn btn-secondary');
540
        $output .= html_writer::empty_tag('input', $attrs);
541
        $output .= html_writer::end_tag('div');
542
        return $output;
543
    }
544
 
545
    /**
546
     * Displays a role mapping interface
547
     *
548
     * @param array $rolemappings
549
     * @param array $roles
550
     * @return string
551
     */
552
    public function role_mappings($rolemappings, $roles) {
553
        $roles[0] = get_string('none');
554
        $output  = html_writer::start_tag('div', array('class' => 'restore-rolemappings'));
555
        $output .= $this->output->heading(get_string('restorerolemappings', 'backup'), 2);
556
        foreach ($rolemappings as $id => $mapping) {
557
            $label = $mapping->name;
558
            $name = 'mapping'.$id;
559
            $selected = $mapping->targetroleid;
560
            $output .= $this->backup_detail_select($label, $name, $roles, $mapping->targetroleid, false, array(), $mapping->description);
561
        }
562
        $output .= html_writer::end_tag('div');
563
        return $output;
564
    }
565
 
566
    /**
567
     * Displays a continue button, overriding core renderer method of the same in order
568
     * to override submission method of the button form
569
     *
570
     * @param string|moodle_url $url
571
     * @param string $method
572
     * @return string
573
     */
574
    public function continue_button($url, $method = 'post') {
575
        if (!($url instanceof moodle_url)) {
576
            $url = new moodle_url($url);
577
        }
578
        if ($method != 'post') {
579
            $method = 'get';
580
        }
581
        $button = new single_button($url, get_string('continue'), $method, single_button::BUTTON_PRIMARY);
582
        $button->class = 'continuebutton';
583
        return $this->render($button);
584
    }
585
    /**
586
     * Print a backup files tree
587
     * @param array $options
588
     * @return string
589
     */
1441 ariadna 590
    public function backup_files_viewer(?array $options = null) {
1 efrain 591
        $files = new backup_files_viewer($options);
592
        return $this->render($files);
593
    }
594
 
595
    /**
596
     * Generate the status indicator markup for display in the
597
     * backup restore file area UI.
598
     *
599
     * @param int $statuscode The status code of the backup.
600
     * @param string $backupid The backup record id.
601
     * @return string|boolean $status The status indicator for the operation.
602
     */
603
    public function get_status_display($statuscode, $backupid, $restoreid=null, $operation='backup') {
604
        if ($statuscode == backup::STATUS_AWAITING
605
            || $statuscode == backup::STATUS_EXECUTING
606
            || $statuscode == backup::STATUS_REQUIRE_CONV) {  // In progress.
607
            $progresssetup = array(
608
                'backupid' => $backupid,
609
                'restoreid' => $restoreid,
610
                'operation' => $operation,
611
                'width' => '100'
612
            );
613
            $status = $this->render_from_template('core/async_backup_progress', $progresssetup);
614
        } else if ($statuscode == backup::STATUS_FINISHED_ERR) { // Error.
615
            $icon = $this->output->render(new \pix_icon('i/delete', get_string('failed', 'backup')));
616
            $status = \html_writer::span($icon, 'action-icon');
617
        } else if ($statuscode == backup::STATUS_FINISHED_OK) { // Complete.
618
            $icon = $this->output->render(new \pix_icon('i/checked', get_string('successful', 'backup')));
619
            $status = \html_writer::span($icon, 'action-icon');
620
        }
621
 
622
        return $status;
623
    }
624
 
625
    /**
626
     * Displays a backup files viewer
627
     *
628
     * @global stdClass $USER
629
     * @param backup_files_viewer $viewer
630
     * @return string
631
     */
632
    public function render_backup_files_viewer(backup_files_viewer $viewer) {
633
 
634
        $files = $viewer->files;
635
        $filestodisplay = false;
636
        foreach ($files as $file) {
637
            if (!$file->is_directory()) {
638
                $filestodisplay = true;
639
                break;
640
            }
641
        }
642
 
643
        $async = \async_helper::is_async_enabled();
644
 
645
        switch($viewer->filearea) {
646
            case 'activity':
647
                $title = get_string('choosefilefromactivitybackup', 'backup');
648
                $description = get_string('choosefilefromactivitybackup_help', 'backup');
649
                $button = get_string('managefiles_activity', 'backup');
650
                $nofilesstring = get_string('restorenofilesbackuparea_activity', 'backup');
651
                break;
652
            case 'course':
653
                $title = get_string('choosefilefromcoursebackup', 'backup');
654
                $description = get_string('choosefilefromcoursebackup_help', 'backup');
655
                $button = get_string('managefiles_course', 'backup');
656
                $nofilesstring = get_string('restorenofilesbackuparea_course', 'backup');
657
                break;
658
            case 'backup':
659
                $title = get_string('choosefilefromuserbackup', 'backup');
660
                $description = get_string('choosefilefromuserbackup_help', 'backup');
661
                $button = get_string('managefiles_backup', 'backup');
662
                $nofilesstring = get_string('restorenofilesbackuparea_backup', 'backup');
663
                break;
664
            case 'automated':
665
                $title = get_string('choosefilefromautomatedbackup', 'backup');
666
                $description = get_string('choosefilefromautomatedbackup_help', 'backup');
667
                $button = get_string('managefiles_automated', 'backup');
668
                $nofilesstring = get_string('restorenofilesbackuparea_automated', 'backup');
669
                break;
670
            default:
671
                $title = '';
672
                $description = '';
673
                $button = get_string('managefiles', 'backup');
674
                $nofilesstring = get_string('restorenofilesbackuparea', 'backup');
675
        }
676
 
677
        $html = html_writer::tag('h3', $title, ['class' => 'mt-6']);
678
        $html .= html_writer::tag('div', $description, ['class' => 'mb-3']);
679
 
680
        if ($filestodisplay || $async) {
681
            $tablehead = [
682
                get_string('filename', 'backup'),
683
                get_string('time'),
684
                get_string('size'),
685
                get_string('download'),
686
                get_string('restore'),
687
            ];
688
            if ($async) {
689
                $tablehead[] = get_string('status', 'backup');
690
            }
691
 
692
            $table = new html_table();
693
            $table->attributes['class'] = 'backup-files-table generaltable';
694
            $table->head = $tablehead;
695
            $table->width = '100%';
696
            $table->data = [];
697
 
698
            // First add in progress asynchronous backups.
699
            // Only if asynchronous backups are enabled.
700
            if ($async) {
701
                $tabledata = [];
702
                $backups = \async_helper::get_async_backups($viewer->filearea, $viewer->filecontext->instanceid);
703
                // For each backup get, new item name, time restore created and progress.
704
                foreach ($backups as $backup) {
705
                    $status = $this->get_status_display($backup->status, $backup->backupid);
706
                    $timecreated = $backup->timecreated;
707
                    $tablerow = [$backup->filename, userdate($timecreated), '-', '-', '-', $status];
708
                    $tabledata[] = $tablerow;
709
                }
710
                $table->data = $tabledata;
711
            }
712
 
713
            // Add completed backups.
714
            foreach ($files as $file) {
715
                if ($file->is_directory()) {
716
                    continue;
717
                }
718
                $fileurl = moodle_url::make_pluginfile_url(
719
                    $file->get_contextid(),
720
                    $file->get_component(),
721
                    $file->get_filearea(),
722
                    null,
723
                    $file->get_filepath(),
724
                    $file->get_filename(),
725
                    true
726
                );
727
                $params = [];
728
                $params['action'] = 'choosebackupfile';
729
                $params['filename'] = $file->get_filename();
730
                $params['filepath'] = $file->get_filepath();
731
                $params['component'] = $file->get_component();
732
                $params['filearea'] = $file->get_filearea();
733
                $params['filecontextid'] = $file->get_contextid();
734
                $params['contextid'] = $viewer->currentcontext->id;
735
                $params['itemid'] = $file->get_itemid();
736
                $restoreurl = new moodle_url('/backup/restorefile.php', $params);
737
                $restorelink = html_writer::link($restoreurl, get_string('restore'));
738
                $downloadlink = html_writer::link($fileurl, get_string('download'));
739
 
740
                // Conditional display of the restore and download links, initially only for the 'automated' filearea.
741
                if ($params['filearea'] == 'automated') {
742
                    if (!has_capability('moodle/restore:viewautomatedfilearea', $viewer->currentcontext)) {
743
                        $restorelink = '';
744
                    }
745
                    if (!can_download_from_backup_filearea($params['filearea'], $viewer->currentcontext)) {
746
                        $downloadlink = '';
747
                    }
748
                }
749
                $tabledata = [
750
                    $file->get_filename(),
751
                    userdate ($file->get_timemodified()),
752
                    display_size ($file->get_filesize()),
753
                    $downloadlink,
754
                    $restorelink,
755
                ];
756
                if ($async) {
757
                    $tabledata[] = $this->get_status_display(backup::STATUS_FINISHED_OK, null);
758
                }
759
 
760
                $table->data[] = $tabledata;
761
            }
762
 
763
            $html .= html_writer::table($table);
764
        } else {
765
            // There are no files to display.
766
            $html .= $this->notification($nofilesstring, 'notifymessage');
767
 
768
        }
769
 
770
        // For automated backups, the ability to manage backup files is controlled by the ability to download them.
771
        // All files must be from the same file area in a backup_files_viewer.
772
        $canmanagebackups = true;
773
        if ($viewer->filearea == 'automated') {
774
            if (!can_download_from_backup_filearea($viewer->filearea, $viewer->currentcontext)) {
775
                $canmanagebackups = false;
776
            }
777
        }
778
 
779
        if ($canmanagebackups) {
780
            $html .= $this->output->single_button(
781
                new moodle_url('/backup/backupfilesedit.php', array(
782
                        'currentcontext' => $viewer->currentcontext->id,
783
                        'contextid' => $viewer->filecontext->id,
784
                        'filearea' => $viewer->filearea,
785
                        'component' => $viewer->component,
786
                        'returnurl' => $this->page->url->out())
787
                ),
788
                $button,
789
                'post'
790
            );
791
        }
792
 
793
        return $html;
794
    }
795
 
796
    /**
797
     * Renders a restore course search object
798
     *
799
     * @param restore_course_search $component
800
     * @return string
801
     */
802
    public function render_restore_course_search(restore_course_search $component) {
803
        $output = html_writer::start_tag('div', array('class' => 'restore-course-search mb-1'));
804
        $output .= html_writer::start_tag('div', array('class' => 'rcs-results table-sm w-75'));
805
 
806
        $table = new html_table();
807
        $table->head = array('', get_string('shortnamecourse'), get_string('fullnamecourse'));
808
        $table->data = array();
809
        if ($component->get_count() !== 0) {
810
            foreach ($component->get_results() as $course) {
811
                $row = new html_table_row();
812
                $row->attributes['class'] = 'rcs-course';
813
                if (!$course->visible) {
814
                    $row->attributes['class'] .= ' dimmed';
815
                }
816
                $id = $this->make_unique_id('restore-course');
817
                $attrs = ['type' => 'radio', 'name' => 'targetid', 'value' => $course->id, 'id' => $id];
818
                if ($course->id == $component->get_current_course_id()) {
819
                    $attrs['checked'] = 'checked';
820
                }
821
                $row->cells = [
822
                    html_writer::empty_tag('input', $attrs),
823
                    html_writer::label(
824
                        format_string($course->shortname, true, ['context' => context_course::instance($course->id)]),
825
                        $id,
826
                        true,
827
                        ['class' => 'd-block']
828
                    ),
829
                    format_string($course->fullname, true, ['context' => context_course::instance($course->id)])
830
                ];
831
                $table->data[] = $row;
832
            }
833
            if ($component->has_more_results()) {
834
                $cell = new html_table_cell(get_string('moreresults', 'backup'));
835
                $cell->colspan = 3;
836
                $cell->attributes['class'] = 'notifyproblem';
837
                $row = new html_table_row(array($cell));
838
                $row->attributes['class'] = 'rcs-course';
839
                $table->data[] = $row;
840
            }
841
        } else {
842
            $cell = new html_table_cell(get_string('nomatchingcourses', 'backup'));
843
            $cell->colspan = 3;
844
            $cell->attributes['class'] = 'notifyproblem';
845
            $row = new html_table_row(array($cell));
846
            $row->attributes['class'] = 'rcs-course';
847
            $table->data[] = $row;
848
        }
849
        $output .= html_writer::table($table);
850
        $output .= html_writer::end_tag('div');
851
 
852
        $data = [
853
            'inform' => true,
854
            'extraclasses' => 'rcs-search mb-3 w-25',
855
            'inputname' => restore_course_search::$VAR_SEARCH,
856
            'searchstring' => get_string('searchcourses'),
857
            'buttonattributes' => [
858
                (object) ['key' => 'name', 'value' => 'searchcourses'],
859
                (object) ['key' => 'value', 'value' => 1],
860
            ],
861
            'query' => $component->get_search(),
862
        ];
863
        $output .= $this->output->render_from_template('core/search_input', $data);
864
 
865
        $output .= html_writer::end_tag('div');
866
        return $output;
867
    }
868
 
869
    /**
870
     * Renders an import course search object
871
     *
872
     * @param import_course_search $component
873
     * @return string
874
     */
875
    public function render_import_course_search(import_course_search $component) {
876
        $output = html_writer::start_tag('div', array('class' => 'import-course-search'));
877
        if ($component->get_count() === 0) {
878
            $output .= $this->output->notification(get_string('nomatchingcourses', 'backup'));
879
 
880
            $output .= html_writer::start_tag('div', ['class' => 'ics-search d-flex flex-wrap align-items-center']);
881
            $attrs = array(
882
                'type' => 'text',
883
                'name' => restore_course_search::$VAR_SEARCH,
884
                'value' => $component->get_search(),
885
                'aria-label' => get_string('searchcourses'),
886
                'placeholder' => get_string('searchcourses'),
887
                'class' => 'form-control'
888
            );
889
            $output .= html_writer::empty_tag('input', $attrs);
890
            $attrs = array(
891
                'type' => 'submit',
892
                'name' => 'searchcourses',
893
                'value' => get_string('search'),
1441 ariadna 894
                'class' => 'btn btn-secondary ms-1'
1 efrain 895
            );
896
            $output .= html_writer::empty_tag('input', $attrs);
897
            $output .= html_writer::end_tag('div');
898
 
899
            $output .= html_writer::end_tag('div');
900
            return $output;
901
        }
902
 
903
        $countstr = '';
904
        if ($component->has_more_results()) {
905
            $countstr = get_string('morecoursesearchresults', 'backup', $component->get_count());
906
        } else {
907
            $countstr = get_string('totalcoursesearchresults', 'backup', $component->get_count());
908
        }
909
 
910
        $output .= html_writer::tag('div', $countstr, array('class' => 'ics-totalresults'));
911
        $output .= html_writer::start_tag('div', array('class' => 'ics-results'));
912
 
913
        $table = new html_table();
914
        $table->head = array('', get_string('shortnamecourse'), get_string('fullnamecourse'));
915
        $table->data = array();
916
        foreach ($component->get_results() as $course) {
917
            $row = new html_table_row();
918
            $row->attributes['class'] = 'ics-course';
919
            if (!$course->visible) {
920
                $row->attributes['class'] .= ' dimmed';
921
            }
922
            $id = $this->make_unique_id('import-course');
923
            $row->cells = [
924
                html_writer::empty_tag('input', ['type' => 'radio', 'name' => 'importid', 'value' => $course->id,
925
                    'id' => $id]),
926
                html_writer::label(
927
                    format_string($course->shortname, true, ['context' => context_course::instance($course->id)]),
928
                    $id,
929
                    true,
930
                    ['class' => 'd-block']
931
                ),
932
                format_string($course->fullname, true, ['context' => context_course::instance($course->id)])
933
            ];
934
            $table->data[] = $row;
935
        }
936
        if ($component->has_more_results()) {
937
            $cell = new html_table_cell(get_string('moreresults', 'backup'));
938
            $cell->colspan = 3;
939
            $cell->attributes['class'] = 'notifyproblem';
940
            $row = new html_table_row(array($cell));
941
            $row->attributes['class'] = 'rcs-course';
942
            $table->data[] = $row;
943
        }
944
        $output .= html_writer::table($table);
945
        $output .= html_writer::end_tag('div');
946
 
947
        $output .= html_writer::start_tag('div', ['class' => 'ics-search d-flex flex-wrap align-items-center']);
948
        $attrs = array(
949
            'type' => 'text',
950
            'name' => restore_course_search::$VAR_SEARCH,
951
            'value' => $component->get_search(),
952
            'aria-label' => get_string('searchcourses'),
953
            'placeholder' => get_string('searchcourses'),
954
            'class' => 'form-control');
955
        $output .= html_writer::empty_tag('input', $attrs);
956
        $attrs = array(
957
            'type' => 'submit',
958
            'name' => 'searchcourses',
959
            'value' => get_string('search'),
1441 ariadna 960
            'class' => 'btn btn-secondary ms-1'
1 efrain 961
        );
962
        $output .= html_writer::empty_tag('input', $attrs);
963
        $output .= html_writer::end_tag('div');
964
 
965
        $output .= html_writer::end_tag('div');
966
        return $output;
967
    }
968
 
969
    /**
970
     * Renders a restore category search object
971
     *
972
     * @param restore_category_search $component
973
     * @return string
974
     */
975
    public function render_restore_category_search(restore_category_search $component) {
976
        $output = html_writer::start_tag('div', array('class' => 'restore-course-search mb-1'));
977
        $output .= html_writer::start_tag('div', array('class' => 'rcs-results table-sm w-75'));
978
 
979
        $table = new html_table();
980
        $table->head = array('', get_string('name'), get_string('description'));
981
        $table->data = array();
982
 
983
        if ($component->get_count() !== 0) {
984
            foreach ($component->get_results() as $category) {
985
                $row = new html_table_row();
986
                $row->attributes['class'] = 'rcs-course';
987
                if (!$category->visible) {
988
                    $row->attributes['class'] .= ' dimmed';
989
                }
990
                $context = context_coursecat::instance($category->id);
991
                $id = $this->make_unique_id('restore-category');
992
                $row->cells = [
993
                    html_writer::empty_tag('input', ['type' => 'radio', 'name' => 'targetid', 'value' => $category->id,
994
                        'id' => $id]),
995
                    html_writer::label(
996
                        format_string($category->name, true, ['context' => context_coursecat::instance($category->id)]),
997
                        $id,
998
                        true,
999
                        ['class' => 'd-block']
1000
                    ),
1001
                    format_text(file_rewrite_pluginfile_urls($category->description, 'pluginfile.php', $context->id,
1002
                        'coursecat', 'description', null), $category->descriptionformat, ['overflowdiv' => true])
1003
                ];
1004
                $table->data[] = $row;
1005
            }
1006
            if ($component->has_more_results()) {
1007
                $cell = new html_table_cell(get_string('moreresults', 'backup'));
1008
                $cell->attributes['class'] = 'notifyproblem';
1009
                $cell->colspan = 3;
1010
                $row = new html_table_row(array($cell));
1011
                $row->attributes['class'] = 'rcs-course';
1012
                $table->data[] = $row;
1013
            }
1014
        } else {
1015
            $cell = new html_table_cell(get_string('nomatchingcourses', 'backup'));
1016
            $cell->colspan = 3;
1017
            $cell->attributes['class'] = 'notifyproblem';
1018
            $row = new html_table_row(array($cell));
1019
            $row->attributes['class'] = 'rcs-course';
1020
            $table->data[] = $row;
1021
        }
1022
        $output .= html_writer::table($table);
1023
        $output .= html_writer::end_tag('div');
1024
 
1025
        $data = [
1026
            'inform' => true,
1027
            'extraclasses' => 'rcs-search mb-3 w-25',
1028
            'inputname' => restore_category_search::$VAR_SEARCH,
1029
            'searchstring' => get_string('searchcoursecategories'),
1030
            'buttonattributes' => [
1031
                (object) ['key' => 'name', 'value' => 'searchcourses'],
1032
                (object) ['key' => 'value', 'value' => 1],
1033
            ],
1034
            'query' => $component->get_search(),
1035
        ];
1036
        $output .= $this->output->render_from_template('core/search_input', $data);
1037
 
1038
        $output .= html_writer::end_tag('div');
1039
        return $output;
1040
    }
1041
 
1042
    /**
1043
     * Get markup to render table for all of a users async
1044
     * in progress restores.
1045
     *
1046
     * @param int $userid The Moodle user id.
1047
     * @param \context $context The Moodle context for these restores.
1048
     * @return string $html The table HTML.
1049
     */
1050
    public function restore_progress_viewer($userid, $context) {
1051
        $tablehead = array(get_string('course'), get_string('time'), get_string('status', 'backup'));
1052
 
1053
        $table = new html_table();
1054
        $table->attributes['class'] = 'backup-files-table generaltable';
1055
        $table->head = $tablehead;
1056
        $tabledata = array();
1057
 
1058
        // Get all in progress async restores for this user.
1059
        $restores = \async_helper::get_async_restores($userid);
1060
 
1061
        // For each backup get, new item name, time restore created and progress.
1062
        foreach ($restores as $restore) {
1063
 
1064
            $restorename = \async_helper::get_restore_name($context);
1065
            $timecreated = $restore->timecreated;
1066
            $status = $this->get_status_display($restore->status, $restore->backupid, $restore->backupid, null, 'restore');
1067
 
1068
            $tablerow = array($restorename, userdate($timecreated), $status);
1069
            $tabledata[] = $tablerow;
1070
        }
1071
 
1072
        $table->data = $tabledata;
1073
        $html = html_writer::table($table);
1074
 
1075
        return $html;
1076
    }
1077
 
1078
    /**
1079
     * Get markup to render table for all of a users course copies.
1080
     *
1081
     * @param int $userid The Moodle user id.
1082
     * @param int $courseid The id of the course to get the backups for.
1083
     * @return string $html The table HTML.
1084
     */
1085
    public function copy_progress_viewer(int $userid, int $courseid): string {
1086
        $tablehead = array(
1087
            get_string('copysource', 'backup'),
1088
            get_string('copydest', 'backup'),
1089
            get_string('time'),
1090
            get_string('copyop', 'backup'),
1091
            get_string('status', 'backup')
1092
        );
1093
 
1094
        $table = new html_table();
1095
        $table->attributes['class'] = 'backup-files-table generaltable';
1096
        $table->head = $tablehead;
1097
 
1098
        $tabledata = array();
1099
 
1100
        // Get all in progress course copies for this user.
1101
        $copies = \copy_helper::get_copies($userid, $courseid);
1102
 
1103
        foreach ($copies as $copy) {
1104
            $sourceurl = new \moodle_url('/course/view.php', array('id' => $copy->sourceid));
1105
 
1106
            $tablerow = array(
1441 ariadna 1107
                html_writer::link($sourceurl, format_string($copy->source, true,
1108
                    ['context' => context_course::instance($copy->sourceid)])),
1109
                format_string($copy->destination, true, ['context' => context_course::instance($copy->sourceid)]),
1 efrain 1110
                userdate($copy->timecreated),
1111
                get_string($copy->operation),
1112
                $this->get_status_display($copy->status, $copy->backupid, $copy->restoreid, $copy->operation)
1113
            );
1114
            $tabledata[] = $tablerow;
1115
        }
1116
 
1117
        $table->data = $tabledata;
1118
        $html = html_writer::table($table);
1119
 
1120
        return $html;
1121
    }
1122
}
1123
 
1124
/**
1125
 * Data structure representing backup files viewer
1126
 *
1127
 * @copyright 2010 Dongsheng Cai
1128
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1129
 * @since     Moodle 2.0
1130
 */
1131
class backup_files_viewer implements renderable {
1132
 
1133
    /**
1134
     * @var array
1135
     */
1136
    public $files;
1137
 
1138
    /**
1139
     * @var context
1140
     */
1141
    public $filecontext;
1142
 
1143
    /**
1144
     * @var string
1145
     */
1146
    public $component;
1147
 
1148
    /**
1149
     * @var string
1150
     */
1151
    public $filearea;
1152
 
1153
    /**
1154
     * @var context
1155
     */
1156
    public $currentcontext;
1157
 
1158
    /**
1159
     * Constructor of backup_files_viewer class
1160
     * @param array $options
1161
     */
1441 ariadna 1162
    public function __construct(?array $options = null) {
1 efrain 1163
        global $CFG, $USER;
1164
        $fs = get_file_storage();
1165
        $this->currentcontext = $options['currentcontext'];
1166
        $this->filecontext    = $options['filecontext'];
1167
        $this->component      = $options['component'];
1168
        $this->filearea       = $options['filearea'];
1169
        $files = $fs->get_area_files($this->filecontext->id, $this->component, $this->filearea, false, 'timecreated');
1170
        $this->files = array_reverse($files);
1171
    }
1172
}