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