Proyectos de Subversion Moodle

Rev

| 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
namespace tool_usertours;
18
 
19
use tool_usertours\local\forms;
20
use tool_usertours\local\table;
21
use core\notification;
22
 
23
/**
24
 * Tour manager.
25
 *
26
 * @package    tool_usertours
27
 * @copyright  2016 Andrew Nicols <andrew@nicols.co.uk>
28
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29
 */
30
class manager {
31
    /**
32
     * @var ACTION_LISTTOURS      The action to get the list of tours.
33
     */
34
    const ACTION_LISTTOURS = 'listtours';
35
 
36
    /**
37
     * @var ACTION_NEWTOUR        The action to create a new tour.
38
     */
39
    const ACTION_NEWTOUR = 'newtour';
40
 
41
    /**
42
     * @var ACTION_EDITTOUR       The action to edit the tour.
43
     */
44
    const ACTION_EDITTOUR = 'edittour';
45
 
46
    /**
47
     * @var ACTION_MOVETOUR The action to move a tour up or down.
48
     */
49
    const ACTION_MOVETOUR = 'movetour';
50
 
51
    /**
52
     * @var ACTION_EXPORTTOUR     The action to export the tour.
53
     */
54
    const ACTION_EXPORTTOUR = 'exporttour';
55
 
56
    /**
57
     * @var ACTION_IMPORTTOUR     The action to import the tour.
58
     */
59
    const ACTION_IMPORTTOUR = 'importtour';
60
 
61
    /**
62
     * @var ACTION_DELETETOUR     The action to delete the tour.
63
     */
64
    const ACTION_DELETETOUR = 'deletetour';
65
 
66
    /**
67
     * @var ACTION_VIEWTOUR       The action to view the tour.
68
     */
69
    const ACTION_VIEWTOUR = 'viewtour';
70
 
71
    /**
72
     * @var ACTION_DUPLICATETOUR     The action to duplicate the tour.
73
     */
74
    const ACTION_DUPLICATETOUR = 'duplicatetour';
75
 
76
    /**
77
     * @var ACTION_NEWSTEP The action to create a new step.
78
     */
79
    const ACTION_NEWSTEP = 'newstep';
80
 
81
    /**
82
     * @var ACTION_EDITSTEP The action to edit step configuration.
83
     */
84
    const ACTION_EDITSTEP = 'editstep';
85
 
86
    /**
87
     * @var ACTION_MOVESTEP The action to move a step up or down.
88
     */
89
    const ACTION_MOVESTEP = 'movestep';
90
 
91
    /**
92
     * @var ACTION_DELETESTEP The action to delete a step.
93
     */
94
    const ACTION_DELETESTEP = 'deletestep';
95
 
96
    /**
97
     * @var ACTION_VIEWSTEP The action to view a step.
98
     */
99
    const ACTION_VIEWSTEP = 'viewstep';
100
 
101
    /**
102
     * @var ACTION_HIDETOUR The action to hide a tour.
103
     */
104
    const ACTION_HIDETOUR = 'hidetour';
105
 
106
    /**
107
     * @var ACTION_SHOWTOUR The action to show a tour.
108
     */
109
    const ACTION_SHOWTOUR = 'showtour';
110
 
111
    /**
112
     * @var ACTION_RESETFORALL
113
     */
114
    const ACTION_RESETFORALL = 'resetforall';
115
 
116
    /**
117
     * @var CONFIG_SHIPPED_TOUR
118
     */
119
    const CONFIG_SHIPPED_TOUR = 'shipped_tour';
120
 
121
    /**
122
     * @var CONFIG_SHIPPED_FILENAME
123
     */
124
    const CONFIG_SHIPPED_FILENAME = 'shipped_filename';
125
 
126
    /**
127
     * @var CONFIG_SHIPPED_VERSION
128
     */
129
    const CONFIG_SHIPPED_VERSION = 'shipped_version';
130
 
131
    /**
132
     * Helper method to initialize admin page, setting appropriate extra URL parameters
133
     *
134
     * @param string $action
135
     */
136
    protected function setup_admin_externalpage(string $action): void {
137
        admin_externalpage_setup('tool_usertours/tours', '', array_filter([
138
            'action' => $action,
139
            'id' => optional_param('id', 0, PARAM_INT),
140
            'tourid' => optional_param('tourid', 0, PARAM_INT),
141
            'direction' => optional_param('direction', 0, PARAM_INT),
142
        ]));
143
    }
144
 
145
    /**
146
     * This is the entry point for this controller class.
147
     *
148
     * @param   string  $action     The action to perform.
149
     */
150
    public function execute($action) {
151
        global $PAGE;
152
        $this->setup_admin_externalpage($action);
153
        $PAGE->set_primary_active_tab('siteadminnode');
154
 
155
        // Add the main content.
156
        switch ($action) {
157
            case self::ACTION_NEWTOUR:
158
            case self::ACTION_EDITTOUR:
159
                $this->edit_tour(optional_param('id', null, PARAM_INT));
160
                break;
161
 
162
            case self::ACTION_MOVETOUR:
163
                $this->move_tour(required_param('id', PARAM_INT));
164
                break;
165
 
166
            case self::ACTION_EXPORTTOUR:
167
                $this->export_tour(required_param('id', PARAM_INT));
168
                break;
169
 
170
            case self::ACTION_IMPORTTOUR:
171
                $this->import_tour();
172
                break;
173
 
174
            case self::ACTION_VIEWTOUR:
175
                $this->view_tour(required_param('id', PARAM_INT));
176
                break;
177
 
178
            case self::ACTION_DUPLICATETOUR:
179
                $this->duplicate_tour(required_param('id', PARAM_INT));
180
                break;
181
 
182
            case self::ACTION_HIDETOUR:
183
                $this->hide_tour(required_param('id', PARAM_INT));
184
                break;
185
 
186
            case self::ACTION_SHOWTOUR:
187
                $this->show_tour(required_param('id', PARAM_INT));
188
                break;
189
 
190
            case self::ACTION_DELETETOUR:
191
                $this->delete_tour(required_param('id', PARAM_INT));
192
                break;
193
 
194
            case self::ACTION_RESETFORALL:
195
                $this->reset_tour_for_all(required_param('id', PARAM_INT));
196
                break;
197
 
198
            case self::ACTION_NEWSTEP:
199
            case self::ACTION_EDITSTEP:
200
                $this->edit_step(optional_param('id', null, PARAM_INT));
201
                break;
202
 
203
            case self::ACTION_MOVESTEP:
204
                $this->move_step(required_param('id', PARAM_INT));
205
                break;
206
 
207
            case self::ACTION_DELETESTEP:
208
                $this->delete_step(required_param('id', PARAM_INT));
209
                break;
210
 
211
            case self::ACTION_LISTTOURS:
212
            default:
213
                $this->print_tour_list();
214
                break;
215
        }
216
    }
217
 
218
    /**
219
     * Print out the page header.
220
     *
221
     * @param   string  $title     The title to display.
222
     */
223
    protected function header($title = null) {
224
        global $OUTPUT;
225
 
226
        // Print the page heading.
227
        echo $OUTPUT->header();
228
 
229
        if ($title === null) {
230
            $title = get_string('tours', 'tool_usertours');
231
        }
232
 
233
        echo $OUTPUT->heading($title);
234
    }
235
 
236
    /**
237
     * Print out the page footer.
238
     *
239
     * @return void
240
     */
241
    protected function footer() {
242
        global $OUTPUT;
243
 
244
        echo $OUTPUT->footer();
245
    }
246
 
247
    /**
248
     * Print the the list of tours.
249
     */
250
    protected function print_tour_list() {
251
        global $PAGE, $OUTPUT;
252
 
253
        $this->header();
254
        echo \html_writer::span(get_string('tourlist_explanation', 'tool_usertours'));
255
        $table = new table\tour_list();
256
        $tours = helper::get_tours();
257
        foreach ($tours as $tour) {
258
            $table->add_data_keyed($table->format_row($tour));
259
        }
260
 
261
        $table->finish_output();
262
        $actions = [
263
            (object) [
264
                'link'  => helper::get_edit_tour_link(),
265
                'linkproperties' => [],
266
                'img'   => 'b/tour-new',
267
                'title' => get_string('newtour', 'tool_usertours'),
268
            ],
269
            (object) [
270
                'link'  => helper::get_import_tour_link(),
271
                'linkproperties' => [],
272
                'img'   => 'b/tour-import',
273
                'title' => get_string('importtour', 'tool_usertours'),
274
            ],
275
            (object) [
276
                'link'  => new \moodle_url('https://moodle.net/search', ['q' => 'user tours']),
277
                'linkproperties' => [
278
                        'target' => '_blank',
279
                    ],
280
                'img'   => 'b/tour-shared',
281
                'title' => get_string('sharedtourslink', 'tool_usertours'),
282
            ],
283
        ];
284
 
285
        echo \html_writer::start_tag('div', [
286
                'class' => 'tour-actions',
287
            ]);
288
 
289
        echo \html_writer::start_tag('ul');
290
        foreach ($actions as $config) {
291
            $action = \html_writer::start_tag('li');
292
            $linkproperties = $config->linkproperties;
293
            $linkproperties['href'] = $config->link;
294
            $action .= \html_writer::start_tag('a', $linkproperties);
295
            $action .= $OUTPUT->pix_icon($config->img, $config->title, 'tool_usertours');
296
            $action .= \html_writer::div($config->title);
297
            $action .= \html_writer::end_tag('a');
298
            $action .= \html_writer::end_tag('li');
299
            echo $action;
300
        }
301
        echo \html_writer::end_tag('ul');
302
        echo \html_writer::end_tag('div');
303
 
304
        // JS for Tour management.
305
        $PAGE->requires->js_call_amd('tool_usertours/managetours', 'setup');
306
        $this->footer();
307
    }
308
 
309
    /**
310
     * Return the edit tour link.
311
     *
312
     * @param   int         $id     The ID of the tour
313
     * @return string
314
     */
315
    protected function get_edit_tour_link($id = null) {
316
        $addlink = helper::get_edit_tour_link($id);
317
        return \html_writer::link($addlink, get_string('newtour', 'tool_usertours'));
318
    }
319
 
320
    /**
321
     * Print the edit tour link.
322
     *
323
     * @param   int         $id     The ID of the tour
324
     */
325
    protected function print_edit_tour_link($id = null) {
326
        echo $this->get_edit_tour_link($id);
327
    }
328
 
329
    /**
330
     * Get the import tour link.
331
     *
332
     * @return string
333
     */
334
    protected function get_import_tour_link() {
335
        $importlink = helper::get_import_tour_link();
336
        return \html_writer::link($importlink, get_string('importtour', 'tool_usertours'));
337
    }
338
 
339
    /**
340
     * Print the edit tour page.
341
     *
342
     * @param   int         $id     The ID of the tour
343
     */
344
    protected function edit_tour($id = null) {
345
        global $PAGE;
346
        if ($id) {
347
            $tour = tour::instance($id);
348
            $PAGE->navbar->add(helper::get_string_from_input($tour->get_name()), $tour->get_edit_link());
349
        } else {
350
            $tour = new tour();
351
            $PAGE->navbar->add(get_string('newtour', 'tool_usertours'), $tour->get_edit_link());
352
        }
353
 
354
        $form = new forms\edittour($tour);
355
 
356
        if ($form->is_cancelled()) {
357
            redirect(helper::get_list_tour_link());
358
        } else if ($data = $form->get_data()) {
359
            // Creating a new tour.
360
            $tour->set_name($data->name);
361
            $tour->set_description($data->description);
362
            $tour->set_pathmatch($data->pathmatch);
363
            $tour->set_enabled(!empty($data->enabled));
364
            $tour->set_endtourlabel($data->endtourlabel);
365
            $tour->set_display_step_numbers(!empty($data->displaystepnumbers));
366
            $tour->set_showtourwhen($data->showtourwhen);
367
 
368
            foreach (configuration::get_defaultable_keys() as $key) {
369
                $tour->set_config($key, $data->$key);
370
            }
371
 
372
            // Save filter values.
373
            foreach (helper::get_all_filters() as $filterclass) {
374
                $filterclass::save_filter_values_from_form($tour, $data);
375
            }
376
 
377
            $tour->persist();
378
 
379
            redirect(helper::get_list_tour_link());
380
        } else {
381
            if (empty($tour)) {
382
                $this->header('newtour');
383
            } else {
384
                if (!empty($tour->get_config(self::CONFIG_SHIPPED_TOUR))) {
385
                    notification::add(get_string('modifyshippedtourwarning', 'tool_usertours'), notification::WARNING);
386
                }
387
 
388
                $tourname = !empty($tour->get_name()) ? helper::get_string_from_input($tour->get_name()) : '';
389
                $this->header($tourname);
390
                $data = $tour->prepare_data_for_form();
391
 
392
                // Prepare filter values for the form.
393
                foreach (helper::get_all_filters() as $filterclass) {
394
                    $filterclass::prepare_filter_values_for_form($tour, $data);
395
                }
396
 
397
                $form->set_data($data);
398
            }
399
 
400
            $form->display();
401
            $this->footer();
402
        }
403
    }
404
 
405
    /**
406
     * Print the export tour page.
407
     *
408
     * @param   int         $id     The ID of the tour
409
     */
410
    protected function export_tour($id) {
411
        $tour = tour::instance($id);
412
 
413
        // Grab the full data record.
414
        $export = $tour->to_record();
415
 
416
        // Remove the id.
417
        unset($export->id);
418
 
419
        // Set the version.
420
        $export->version = get_config('tool_usertours', 'version');
421
 
422
        // Step export.
423
        $export->steps = [];
424
        foreach ($tour->get_steps() as $step) {
425
            $record = $step->to_record(true);
426
            unset($record->id);
427
            unset($record->tourid);
428
 
429
            $export->steps[] = $record;
430
        }
431
 
432
        $exportstring = json_encode($export);
433
 
434
        $filename = 'tour_export_' . $tour->get_id() . '_' . time() . '.json';
435
 
436
        // Force download.
437
        send_file($exportstring, $filename, 0, 0, true, true);
438
    }
439
 
440
    /**
441
     * Handle tour import.
442
     */
443
    protected function import_tour() {
444
        global $PAGE;
445
        $PAGE->navbar->add(get_string('importtour', 'tool_usertours'), helper::get_import_tour_link());
446
 
447
        $form = new forms\importtour();
448
 
449
        if ($form->is_cancelled()) {
450
            redirect(helper::get_list_tour_link());
451
        } else if ($form->get_data()) {
452
            // Importing a tour.
453
            $tourconfigraw = $form->get_file_content('tourconfig');
454
            $tour = self::import_tour_from_json($tourconfigraw);
455
 
456
            redirect($tour->get_view_link());
457
        } else {
458
            $this->header();
459
            $form->display();
460
            $this->footer();
461
        }
462
    }
463
 
464
    /**
465
     * Print the view tour page.
466
     *
467
     * @param   int         $tourid     The ID of the tour to display.
468
     */
469
    protected function view_tour($tourid) {
470
        global $PAGE;
471
        $tour = helper::get_tour($tourid);
472
        $tourname = helper::get_string_from_input($tour->get_name());
473
 
474
        $PAGE->navbar->add($tourname, $tour->get_view_link());
475
 
476
        $this->header($tourname);
477
        echo \html_writer::span(get_string('viewtour_info', 'tool_usertours', [
478
                'tourname'  => $tourname,
479
                'path'      => $tour->get_pathmatch(),
480
            ]));
481
        echo \html_writer::div(get_string('viewtour_edit', 'tool_usertours', [
482
                'editlink'  => $tour->get_edit_link()->out(),
483
                'resetlink' => $tour->get_reset_link()->out(),
484
            ]));
485
 
486
        $table = new table\step_list($tourid);
487
        foreach ($tour->get_steps() as $step) {
488
            $table->add_data_keyed($table->format_row($step));
489
        }
490
 
491
        $table->finish_output();
492
        $this->print_edit_step_link($tourid);
493
 
494
        // JS for Step management.
495
        $PAGE->requires->js_call_amd('tool_usertours/managesteps', 'setup');
496
 
497
        $this->footer();
498
    }
499
 
500
    /**
501
     * Duplicate an existing tour.
502
     *
503
     * @param   int         $tourid     The ID of the tour to duplicate.
504
     */
505
    protected function duplicate_tour($tourid) {
506
        $tour = helper::get_tour($tourid);
507
 
508
        $export = $tour->to_record();
509
        // Remove the id.
510
        unset($export->id);
511
 
512
        // Set the version.
513
        $export->version = get_config('tool_usertours', 'version');
514
 
515
        $export->name = get_string('duplicatetour_name', 'tool_usertours', $export->name);
516
 
517
        // Step export.
518
        $export->steps = [];
519
        foreach ($tour->get_steps() as $step) {
520
            $record = $step->to_record(true);
521
            unset($record->id);
522
            unset($record->tourid);
523
 
524
            $export->steps[] = $record;
525
        }
526
 
527
        $exportstring = json_encode($export);
528
        $newtour = self::import_tour_from_json($exportstring);
529
 
530
        redirect($newtour->get_view_link());
531
    }
532
 
533
    /**
534
     * Show the tour.
535
     *
536
     * @param   int         $tourid     The ID of the tour to display.
537
     */
538
    protected function show_tour($tourid) {
539
        $this->show_hide_tour($tourid, 1);
540
    }
541
 
542
    /**
543
     * Hide the tour.
544
     *
545
     * @param   int         $tourid     The ID of the tour to display.
546
     */
547
    protected function hide_tour($tourid) {
548
        $this->show_hide_tour($tourid, 0);
549
    }
550
 
551
    /**
552
     * Show or Hide the tour.
553
     *
554
     * @param   int         $tourid     The ID of the tour to display.
555
     * @param   int         $visibility The intended visibility.
556
     */
557
    protected function show_hide_tour($tourid, $visibility) {
558
        global $DB;
559
 
560
        require_sesskey();
561
 
562
        $tour = $DB->get_record('tool_usertours_tours', ['id' => $tourid]);
563
        $tour->enabled = $visibility;
564
        $DB->update_record('tool_usertours_tours', $tour);
565
 
566
        redirect(helper::get_list_tour_link());
567
    }
568
 
569
    /**
570
     * Delete the tour.
571
     *
572
     * @param   int         $tourid     The ID of the tour to remove.
573
     */
574
    protected function delete_tour($tourid) {
575
        require_sesskey();
576
 
577
        $tour = tour::instance($tourid);
578
        $tour->remove();
579
 
580
        redirect(helper::get_list_tour_link());
581
    }
582
 
583
    /**
584
     * Reset the tour state for all users.
585
     *
586
     * @param   int         $tourid     The ID of the tour to remove.
587
     */
588
    protected function reset_tour_for_all($tourid) {
589
        require_sesskey();
590
 
591
        $tour = tour::instance($tourid);
592
        $tour->mark_major_change();
593
 
594
        redirect(helper::get_view_tour_link($tourid), get_string('tour_resetforall', 'tool_usertours'));
595
    }
596
 
597
    /**
598
     * Get all tours for the current page URL.
599
     *
600
     * @param   bool        $reset      Forcibly update the current tours
601
     * @return  array
602
     */
603
    public static function get_current_tours($reset = false): array {
604
        global $PAGE;
605
 
606
        static $tours = false;
607
 
608
        if ($tours === false || $reset) {
609
            $tours = self::get_matching_tours($PAGE->url);
610
        }
611
 
612
        return $tours;
613
    }
614
 
615
    /**
616
     * Get all tours matching the specified URL.
617
     *
618
     * @param   moodle_url  $pageurl        The URL to match.
619
     * @return  array
620
     */
621
    public static function get_matching_tours(\moodle_url $pageurl): array {
622
        global $PAGE;
623
 
624
        if (\core_user::awaiting_action()) {
625
            // User not fully ready to use the site. Don't show any tours, we need the user to get properly set up so
626
            // that all require_login() and other bits work as expected.
627
            return [];
628
        }
629
 
630
        $tours = cache::get_matching_tourdata($pageurl);
631
 
632
        $matches = [];
633
        if ($tours) {
634
            $filters = helper::get_all_filters();
635
            foreach ($tours as $record) {
636
                $tour = tour::load_from_record($record);
637
                if ($tour->is_enabled() && $tour->matches_all_filters($PAGE->context, $filters)) {
638
                    $matches[] = $tour;
639
                }
640
            }
641
        }
642
 
643
        return $matches;
644
    }
645
 
646
    /**
647
     * Import the provided tour JSON.
648
     *
649
     * @param   string      $json           The tour configuration.
650
     * @return  tour
651
     */
652
    public static function import_tour_from_json($json) {
653
        $tourconfig = json_decode($json);
654
 
655
        // We do not use this yet - we may do in the future.
656
        unset($tourconfig->version);
657
 
658
        $steps = $tourconfig->steps;
659
        unset($tourconfig->steps);
660
 
661
        $tourconfig->id = null;
662
        $tourconfig->sortorder = null;
663
        $tour = tour::load_from_record($tourconfig, true);
664
        $tour->persist(true);
665
 
666
        // Ensure that steps are orderered by their sortorder.
667
        \core_collator::asort_objects_by_property($steps, 'sortorder', \core_collator::SORT_NUMERIC);
668
 
669
        foreach ($steps as $stepconfig) {
670
            $stepconfig->id = null;
671
            $stepconfig->tourid = $tour->get_id();
672
            $step = step::load_from_record($stepconfig, true, true);
673
            $step->persist(true);
674
        }
675
 
676
        return $tour;
677
    }
678
 
679
    /**
680
     * Helper to fetch the renderer.
681
     *
682
     * @return  renderer
683
     */
684
    protected function get_renderer() {
685
        global $PAGE;
686
        return $PAGE->get_renderer('tool_usertours');
687
    }
688
 
689
    /**
690
     * Print the edit step link.
691
     *
692
     * @param   int     $tourid     The ID of the tour.
693
     * @param   int     $stepid     The ID of the step.
694
     * @return  string
695
     */
696
    protected function print_edit_step_link($tourid, $stepid = null) {
697
        $addlink = helper::get_edit_step_link($tourid, $stepid);
698
        $attributes = [];
699
        if (empty($stepid)) {
700
            $attributes['class'] = 'createstep';
701
        }
702
        echo \html_writer::link($addlink, get_string('newstep', 'tool_usertours'), $attributes);
703
    }
704
 
705
    /**
706
     * Display the edit step form for the specified step.
707
     *
708
     * @param   int     $id     The step to edit.
709
     */
710
    protected function edit_step($id) {
711
        global $PAGE;
712
 
713
        if (isset($id)) {
714
            $step = step::instance($id);
715
        } else {
716
            $step = new step();
717
            $step->set_tourid(required_param('tourid', PARAM_INT));
718
        }
719
 
720
        $tour = $step->get_tour();
721
 
722
        if (!empty($tour->get_config(self::CONFIG_SHIPPED_TOUR))) {
723
            notification::add(get_string('modifyshippedtourwarning', 'tool_usertours'), notification::WARNING);
724
        }
725
 
726
        $PAGE->navbar->add(helper::get_string_from_input($tour->get_name()), $tour->get_view_link());
727
        if (isset($id)) {
728
            $PAGE->navbar->add(helper::get_string_from_input($step->get_title()), $step->get_edit_link());
729
        } else {
730
            $PAGE->navbar->add(get_string('newstep', 'tool_usertours'), $step->get_edit_link());
731
        }
732
 
733
        $form = new forms\editstep($step->get_edit_link(), $step);
734
        if ($form->is_cancelled()) {
735
            redirect($step->get_tour()->get_view_link());
736
        } else if ($data = $form->get_data()) {
737
            $step->handle_form_submission($form, $data);
738
            $step->get_tour()->reset_step_sortorder();
739
            redirect($step->get_tour()->get_view_link());
740
        } else {
741
            if (empty($id)) {
742
                $this->header(get_string('newstep', 'tool_usertours'));
743
            } else {
744
                $this->header(get_string('editstep', 'tool_usertours', helper::get_string_from_input($step->get_title())));
745
            }
746
            $form->set_data($step->prepare_data_for_form());
747
 
748
            $form->display();
749
            $this->footer();
750
        }
751
    }
752
 
753
    /**
754
     * Move a tour up or down and redirect once complete.
755
     *
756
     * @param   int     $id     The tour to move.
757
     */
758
    protected function move_tour($id) {
759
        require_sesskey();
760
 
761
        $direction = required_param('direction', PARAM_INT);
762
 
763
        $tour = tour::instance($id);
764
        self::_move_tour($tour, $direction);
765
 
766
        redirect(helper::get_list_tour_link());
767
    }
768
 
769
    /**
770
     * Move a tour up or down.
771
     *
772
     * @param   tour    $tour   The tour to move.
773
     *
774
     * @param   int     $direction
775
     */
776
    protected static function _move_tour(tour $tour, $direction) {
777
        // We can't move the first tour higher, nor the last tour any lower.
778
        if (
779
            ($tour->is_first_tour() && $direction == helper::MOVE_UP) ||
780
                ($tour->is_last_tour() && $direction == helper::MOVE_DOWN)
781
        ) {
782
            return;
783
        }
784
 
785
        $currentsortorder   = $tour->get_sortorder();
786
        $targetsortorder    = $currentsortorder + $direction;
787
 
788
        $swapwith = helper::get_tour_from_sortorder($targetsortorder);
789
 
790
        // Set the sort order to something out of the way.
791
        $tour->set_sortorder(-1);
792
        $tour->persist();
793
 
794
        // Swap the two sort orders.
795
        $swapwith->set_sortorder($currentsortorder);
796
        $swapwith->persist();
797
 
798
        $tour->set_sortorder($targetsortorder);
799
        $tour->persist();
800
    }
801
 
802
    /**
803
     * Move a step up or down.
804
     *
805
     * @param   int     $id     The step to move.
806
     */
807
    protected function move_step($id) {
808
        require_sesskey();
809
 
810
        $direction = required_param('direction', PARAM_INT);
811
 
812
        $step = step::instance($id);
813
        $currentsortorder   = $step->get_sortorder();
814
        $targetsortorder    = $currentsortorder + $direction;
815
 
816
        $tour = $step->get_tour();
817
        $swapwith = helper::get_step_from_sortorder($tour->get_id(), $targetsortorder);
818
 
819
        // Set the sort order to something out of the way.
820
        $step->set_sortorder(-1);
821
        $step->persist();
822
 
823
        // Swap the two sort orders.
824
        $swapwith->set_sortorder($currentsortorder);
825
        $swapwith->persist();
826
 
827
        $step->set_sortorder($targetsortorder);
828
        $step->persist();
829
 
830
        // Reset the sort order.
831
        $tour->reset_step_sortorder();
832
        redirect($tour->get_view_link());
833
    }
834
 
835
    /**
836
     * Delete the step.
837
     *
838
     * @param   int         $stepid     The ID of the step to remove.
839
     */
840
    protected function delete_step($stepid) {
841
        require_sesskey();
842
 
843
        $step = step::instance($stepid);
844
        $tour = $step->get_tour();
845
 
846
        $step->remove();
847
        redirect($tour->get_view_link());
848
    }
849
 
850
    /**
851
     * Make sure all of the default tours that are shipped with Moodle are created
852
     * and up to date with the latest version.
853
     */
854
    public static function update_shipped_tours() {
855
        global $DB, $CFG;
856
 
857
        // A list of tours that are shipped with Moodle. They are in
858
        // the format filename => version. The version value needs to
859
        // be increased if the tour has been updated.
860
        $shippedtours = [
861
            '40_tour_navigation_dashboard.json' => 4,
862
            '40_tour_navigation_mycourse.json' => 5,
863
            '40_tour_navigation_course_teacher.json' => 3,
864
            '40_tour_navigation_course_student.json' => 3,
865
            '42_tour_gradebook_grader_report.json' => 1,
866
        ];
867
 
868
        // These are tours that we used to ship but don't ship any longer.
869
        // We do not remove them, but we do disable them.
870
        $unshippedtours = [
871
            // Formerly included in Moodle 3.2.0.
872
            'boost_administrator.json' => 1,
873
            'boost_course_view.json' => 1,
874
 
875
            // Formerly included in Moodle 3.6.0.
876
            '36_dashboard.json' => 3,
877
            '36_messaging.json' => 3,
878
 
879
            // Formerly included in Moodle 3.11.0.
880
            '311_activity_information_activity_page_student.json' => 2,
881
            '311_activity_information_activity_page_teacher.json' => 2,
882
            '311_activity_information_course_page_student.json' => 2,
883
            '311_activity_information_course_page_teacher.json' => 2,
884
        ];
885
 
886
        $existingtourrecords = $DB->get_recordset('tool_usertours_tours');
887
 
888
        // Get all of the existing shipped tours and check if they need to be
889
        // updated.
890
        foreach ($existingtourrecords as $tourrecord) {
891
            $tour = tour::load_from_record($tourrecord);
892
 
893
            if (!empty($tour->get_config(self::CONFIG_SHIPPED_TOUR))) {
894
                $filename = $tour->get_config(self::CONFIG_SHIPPED_FILENAME);
895
                $version = $tour->get_config(self::CONFIG_SHIPPED_VERSION);
896
 
897
                // If we know about this tour (otherwise leave it as is).
898
                if (isset($shippedtours[$filename])) {
899
                    // And the version in the DB is an older version.
900
                    if ($version < $shippedtours[$filename]) {
901
                        // Remove the old version because it's been updated
902
                        // and needs to be recreated.
903
                        $tour->remove();
904
                    } else {
905
                        // The tour has not been updated so we don't need to
906
                        // do anything with it.
907
                        unset($shippedtours[$filename]);
908
                    }
909
                }
910
 
911
                if (isset($unshippedtours[$filename])) {
912
                    if ($version <= $unshippedtours[$filename]) {
913
                        $tour = tour::instance($tour->get_id());
914
                        $tour->set_enabled(tour::DISABLED);
915
                        $tour->persist();
916
                    }
917
                }
918
            }
919
        }
920
        $existingtourrecords->close();
921
 
922
        // Ensure we correct the sortorder in any existing tours, prior to adding latest shipped tours.
923
        helper::reset_tour_sortorder();
924
 
925
        foreach (array_reverse($shippedtours) as $filename => $version) {
926
            $filepath = $CFG->dirroot . "/{$CFG->admin}/tool/usertours/tours/" . $filename;
927
            $tourjson = file_get_contents($filepath);
928
            $tour = self::import_tour_from_json($tourjson);
929
 
930
            // Set some additional config data to record that this tour was
931
            // added as a shipped tour.
932
            $tour->set_config(self::CONFIG_SHIPPED_TOUR, true);
933
            $tour->set_config(self::CONFIG_SHIPPED_FILENAME, $filename);
934
            $tour->set_config(self::CONFIG_SHIPPED_VERSION, $version);
935
 
936
            // Bump new tours to the top of the list.
937
            while ($tour->get_sortorder() > 0) {
938
                self::_move_tour($tour, helper::MOVE_UP);
939
            }
940
 
941
            if (defined('BEHAT_SITE_RUNNING') || (defined('PHPUNIT_TEST') && PHPUNIT_TEST)) {
942
                // Disable this tour if this is behat or phpunit.
943
                $tour->set_enabled(false);
944
            }
945
 
946
            $tour->persist();
947
        }
948
    }
949
}