See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 * Renderer for core_admin subsystem 19 * 20 * @package core 21 * @subpackage admin 22 * @copyright 2011 David Mudrak <david@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 29 /** 30 * Standard HTML output renderer for core_admin subsystem 31 */ 32 class core_admin_renderer extends plugin_renderer_base { 33 34 /** 35 * Display the 'Do you acknowledge the terms of the GPL' page. The first page 36 * during install. 37 * @return string HTML to output. 38 */ 39 public function install_licence_page() { 40 global $CFG; 41 $output = ''; 42 43 $copyrightnotice = text_to_html(get_string('gpl3')); 44 $copyrightnotice = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $copyrightnotice); // extremely ugly validation hack 45 46 $continue = new single_button(new moodle_url($this->page->url, array( 47 'lang' => $CFG->lang, 'agreelicense' => 1)), get_string('continue'), 'get'); 48 49 $output .= $this->header(); 50 $output .= $this->heading('<a href="http://moodle.org">Moodle</a> - Modular Object-Oriented Dynamic Learning Environment'); 51 $output .= $this->heading(get_string('copyrightnotice')); 52 $output .= $this->box($copyrightnotice, 'copyrightnotice'); 53 $output .= html_writer::empty_tag('br'); 54 $output .= $this->confirm(get_string('doyouagree'), $continue, "http://docs.moodle.org/dev/License"); 55 $output .= $this->footer(); 56 57 return $output; 58 } 59 60 /** 61 * Display page explaining proper upgrade process, 62 * there can not be any PHP file leftovers... 63 * 64 * @return string HTML to output. 65 */ 66 public function upgrade_stale_php_files_page() { 67 $output = ''; 68 $output .= $this->header(); 69 $output .= $this->heading(get_string('upgradestalefiles', 'admin')); 70 $output .= $this->box_start('generalbox', 'notice'); 71 $output .= format_text(get_string('upgradestalefilesinfo', 'admin', get_docs_url('Upgrading')), FORMAT_MARKDOWN); 72 $output .= html_writer::empty_tag('br'); 73 $output .= html_writer::tag('div', $this->single_button($this->page->url, get_string('reload'), 'get'), array('class' => 'buttons')); 74 $output .= $this->box_end(); 75 $output .= $this->footer(); 76 77 return $output; 78 } 79 80 /** 81 * Display the 'environment check' page that is displayed during install. 82 * @param int $maturity 83 * @param boolean $envstatus final result of the check (true/false) 84 * @param array $environment_results array of results gathered 85 * @param string $release moodle release 86 * @return string HTML to output. 87 */ 88 public function install_environment_page($maturity, $envstatus, $environment_results, $release) { 89 global $CFG; 90 $output = ''; 91 92 $output .= $this->header(); 93 $output .= $this->maturity_warning($maturity); 94 $output .= $this->heading("Moodle $release"); 95 $output .= $this->release_notes_link(); 96 97 $output .= $this->environment_check_table($envstatus, $environment_results); 98 99 if (!$envstatus) { 100 $output .= $this->upgrade_reload(new moodle_url($this->page->url, array('agreelicense' => 1, 'lang' => $CFG->lang))); 101 } else { 102 $output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess'); 103 $output .= $this->continue_button(new moodle_url($this->page->url, array( 104 'agreelicense' => 1, 'confirmrelease' => 1, 'lang' => $CFG->lang))); 105 } 106 107 $output .= $this->footer(); 108 return $output; 109 } 110 111 /** 112 * Displays the list of plugins with unsatisfied dependencies 113 * 114 * @param double|string|int $version Moodle on-disk version 115 * @param array $failed list of plugins with unsatisfied dependecies 116 * @param moodle_url $reloadurl URL of the page to recheck the dependencies 117 * @return string HTML 118 */ 119 public function unsatisfied_dependencies_page($version, array $failed, moodle_url $reloadurl) { 120 $output = ''; 121 122 $output .= $this->header(); 123 $output .= $this->heading(get_string('pluginscheck', 'admin')); 124 $output .= $this->warning(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed))))); 125 $output .= $this->plugins_check_table(core_plugin_manager::instance(), $version, array('xdep' => true)); 126 $output .= $this->warning(get_string('pluginschecktodo', 'admin')); 127 $output .= $this->continue_button($reloadurl); 128 129 $output .= $this->footer(); 130 131 return $output; 132 } 133 134 /** 135 * Display the 'You are about to upgrade Moodle' page. The first page 136 * during upgrade. 137 * @param string $strnewversion 138 * @param int $maturity 139 * @param string $testsite 140 * @return string HTML to output. 141 */ 142 public function upgrade_confirm_page($strnewversion, $maturity, $testsite) { 143 $output = ''; 144 145 $continueurl = new moodle_url($this->page->url, array('confirmupgrade' => 1, 'cache' => 0)); 146 $continue = new single_button($continueurl, get_string('continue'), 'get'); 147 $cancelurl = new moodle_url('/admin/index.php'); 148 149 $output .= $this->header(); 150 $output .= $this->maturity_warning($maturity); 151 $output .= $this->test_site_warning($testsite); 152 $output .= $this->confirm(get_string('upgradesure', 'admin', $strnewversion), $continue, $cancelurl); 153 $output .= $this->footer(); 154 155 return $output; 156 } 157 158 /** 159 * Display the environment page during the upgrade process. 160 * @param string $release 161 * @param boolean $envstatus final result of env check (true/false) 162 * @param array $environment_results array of results gathered 163 * @return string HTML to output. 164 */ 165 public function upgrade_environment_page($release, $envstatus, $environment_results) { 166 global $CFG; 167 $output = ''; 168 169 $output .= $this->header(); 170 $output .= $this->heading("Moodle $release"); 171 $output .= $this->release_notes_link(); 172 $output .= $this->environment_check_table($envstatus, $environment_results); 173 174 if (!$envstatus) { 175 $output .= $this->upgrade_reload(new moodle_url($this->page->url, array('confirmupgrade' => 1, 'cache' => 0))); 176 177 } else { 178 $output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess'); 179 180 if (empty($CFG->skiplangupgrade) and current_language() !== 'en') { 181 $output .= $this->box(get_string('langpackwillbeupdated', 'admin'), 'generalbox', 'notice'); 182 } 183 184 $output .= $this->continue_button(new moodle_url($this->page->url, array( 185 'confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0))); 186 } 187 188 $output .= $this->footer(); 189 190 return $output; 191 } 192 193 /** 194 * Display the upgrade page that lists all the plugins that require attention. 195 * @param core_plugin_manager $pluginman provides information about the plugins. 196 * @param \core\update\checker $checker provides information about available updates. 197 * @param int $version the version of the Moodle code from version.php. 198 * @param bool $showallplugins 199 * @param moodle_url $reloadurl 200 * @param moodle_url $continueurl 201 * @return string HTML to output. 202 */ 203 public function upgrade_plugin_check_page(core_plugin_manager $pluginman, \core\update\checker $checker, 204 $version, $showallplugins, $reloadurl, $continueurl) { 205 206 $output = ''; 207 208 $output .= $this->header(); 209 $output .= $this->box_start('generalbox', 'plugins-check-page'); 210 $output .= html_writer::tag('p', get_string('pluginchecknotice', 'core_plugin'), array('class' => 'page-description')); 211 $output .= $this->check_for_updates_button($checker, $reloadurl); 212 $output .= $this->missing_dependencies($pluginman); 213 $output .= $this->plugins_check_table($pluginman, $version, array('full' => $showallplugins)); 214 $output .= $this->box_end(); 215 $output .= $this->upgrade_reload($reloadurl); 216 217 if ($pluginman->some_plugins_updatable()) { 218 $output .= $this->container_start('upgradepluginsinfo'); 219 $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin')); 220 $output .= $this->container_end(); 221 } 222 223 $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get'); 224 $button->class = 'continuebutton'; 225 $output .= $this->render($button); 226 $output .= $this->footer(); 227 228 return $output; 229 } 230 231 /** 232 * Display a page to confirm plugin installation cancelation. 233 * 234 * @param array $abortable list of \core\update\plugininfo 235 * @param moodle_url $continue 236 * @return string 237 */ 238 public function upgrade_confirm_abort_install_page(array $abortable, moodle_url $continue) { 239 240 $pluginman = core_plugin_manager::instance(); 241 242 if (empty($abortable)) { 243 // The UI should not allow this. 244 throw new moodle_exception('err_no_plugin_install_abortable', 'core_plugin'); 245 } 246 247 $out = $this->output->header(); 248 $out .= $this->output->heading(get_string('cancelinstallhead', 'core_plugin'), 3); 249 $out .= $this->output->container(get_string('cancelinstallinfo', 'core_plugin'), 'cancelinstallinfo'); 250 251 foreach ($abortable as $pluginfo) { 252 $out .= $this->output->heading($pluginfo->displayname.' ('.$pluginfo->component.')', 4); 253 $out .= $this->output->container(get_string('cancelinstallinfodir', 'core_plugin', $pluginfo->rootdir)); 254 if ($repotype = $pluginman->plugin_external_source($pluginfo->component)) { 255 $out .= $this->output->container(get_string('uninstalldeleteconfirmexternal', 'core_plugin', $repotype), 256 'alert alert-warning mt-2'); 257 } 258 } 259 260 $out .= $this->plugins_management_confirm_buttons($continue, $this->page->url); 261 $out .= $this->output->footer(); 262 263 return $out; 264 } 265 266 /** 267 * Display the admin notifications page. 268 * @param int $maturity 269 * @param bool $insecuredataroot warn dataroot is invalid 270 * @param bool $errorsdisplayed warn invalid dispaly error setting 271 * @param bool $cronoverdue warn cron not running 272 * @param bool $dbproblems warn db has problems 273 * @param bool $maintenancemode warn in maintenance mode 274 * @param bool $buggyiconvnomb warn iconv problems 275 * @param array|null $availableupdates array of \core\update\info objects or null 276 * @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown) 277 * @param string[] $cachewarnings An array containing warnings from the Cache API. 278 * @param array $eventshandlers Events 1 API handlers. 279 * @param bool $themedesignermode Warn about the theme designer mode. 280 * @param bool $devlibdir Warn about development libs directory presence. 281 * @param bool $mobileconfigured Whether the mobile web services have been enabled 282 * @param bool $overridetossl Whether or not ssl is being forced. 283 * @param bool $invalidforgottenpasswordurl Whether the forgotten password URL does not link to a valid URL. 284 * @param bool $croninfrequent If true, warn that cron hasn't run in the past few minutes 285 * @param bool $showcampaigncontent Whether the campaign content should be visible or not. 286 * @param bool $showfeedbackencouragement Whether the feedback encouragement content should be displayed or not. 287 * 288 * @return string HTML to output. 289 */ 290 public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, 291 $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch, 292 $buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0, 293 $themedesignermode = false, $devlibdir = false, $mobileconfigured = false, 294 $overridetossl = false, $invalidforgottenpasswordurl = false, $croninfrequent = false, 295 $showcampaigncontent = false, bool $showfeedbackencouragement = false) { 296 297 global $CFG; 298 $output = ''; 299 300 $output .= $this->header(); 301 $output .= $this->maturity_info($maturity); 302 $output .= $this->legacy_log_store_writing_error(); 303 $output .= empty($CFG->disableupdatenotifications) ? $this->available_updates($availableupdates, $availableupdatesfetch) : ''; 304 $output .= $this->insecure_dataroot_warning($insecuredataroot); 305 $output .= $this->development_libs_directories_warning($devlibdir); 306 $output .= $this->themedesignermode_warning($themedesignermode); 307 $output .= $this->display_errors_warning($errorsdisplayed); 308 $output .= $this->buggy_iconv_warning($buggyiconvnomb); 309 $output .= $this->cron_overdue_warning($cronoverdue); 310 $output .= $this->cron_infrequent_warning($croninfrequent); 311 $output .= $this->db_problems($dbproblems); 312 $output .= $this->maintenance_mode_warning($maintenancemode); 313 $output .= $this->overridetossl_warning($overridetossl); 314 $output .= $this->cache_warnings($cachewarnings); 315 $output .= $this->events_handlers($eventshandlers); 316 $output .= $this->registration_warning($registered); 317 $output .= $this->mobile_configuration_warning($mobileconfigured); 318 $output .= $this->forgotten_password_url_warning($invalidforgottenpasswordurl); 319 $output .= $this->userfeedback_encouragement($showfeedbackencouragement); 320 $output .= $this->campaign_content($showcampaigncontent); 321 322 ////////////////////////////////////////////////////////////////////////////////////////////////// 323 //// IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE /// 324 $output .= $this->moodle_copyright(); 325 ////////////////////////////////////////////////////////////////////////////////////////////////// 326 327 $output .= $this->footer(); 328 329 return $output; 330 } 331 332 /** 333 * Display the plugin management page (admin/plugins.php). 334 * 335 * The filtering options array may contain following items: 336 * bool contribonly - show only contributed extensions 337 * bool updatesonly - show only plugins with an available update 338 * 339 * @param core_plugin_manager $pluginman 340 * @param \core\update\checker $checker 341 * @param array $options filtering options 342 * @return string HTML to output. 343 */ 344 public function plugin_management_page(core_plugin_manager $pluginman, \core\update\checker $checker, array $options = array()) { 345 346 $output = ''; 347 348 $output .= $this->header(); 349 $output .= $this->heading(get_string('pluginsoverview', 'core_admin')); 350 $output .= $this->check_for_updates_button($checker, $this->page->url); 351 $output .= $this->plugins_overview_panel($pluginman, $options); 352 $output .= $this->plugins_control_panel($pluginman, $options); 353 $output .= $this->footer(); 354 355 return $output; 356 } 357 358 /** 359 * Renders a button to fetch for available updates. 360 * 361 * @param \core\update\checker $checker 362 * @param moodle_url $reloadurl 363 * @return string HTML 364 */ 365 public function check_for_updates_button(\core\update\checker $checker, $reloadurl) { 366 367 $output = ''; 368 369 if ($checker->enabled()) { 370 $output .= $this->container_start('checkforupdates mb-4'); 371 $output .= $this->single_button( 372 new moodle_url($reloadurl, array('fetchupdates' => 1)), 373 get_string('checkforupdates', 'core_plugin') 374 ); 375 if ($timefetched = $checker->get_last_timefetched()) { 376 $timefetched = userdate($timefetched, get_string('strftimedatetime', 'core_langconfig')); 377 $output .= $this->container(get_string('checkforupdateslast', 'core_plugin', $timefetched), 378 'lasttimefetched small text-muted mt-1'); 379 } 380 $output .= $this->container_end(); 381 } 382 383 return $output; 384 } 385 386 /** 387 * Display a page to confirm the plugin uninstallation. 388 * 389 * @param core_plugin_manager $pluginman 390 * @param \core\plugininfo\base $pluginfo 391 * @param moodle_url $continueurl URL to continue after confirmation 392 * @param moodle_url $cancelurl URL to to go if cancelled 393 * @return string 394 */ 395 public function plugin_uninstall_confirm_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo, moodle_url $continueurl, moodle_url $cancelurl) { 396 $output = ''; 397 398 $pluginname = $pluginman->plugin_name($pluginfo->component); 399 400 $confirm = '<p>' . get_string('uninstallconfirm', 'core_plugin', array('name' => $pluginname)) . '</p>'; 401 if ($extraconfirm = $pluginfo->get_uninstall_extra_warning()) { 402 $confirm .= $extraconfirm; 403 } 404 405 $output .= $this->output->header(); 406 $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname))); 407 $output .= $this->output->confirm($confirm, $continueurl, $cancelurl); 408 $output .= $this->output->footer(); 409 410 return $output; 411 } 412 413 /** 414 * Display a page with results of plugin uninstallation and offer removal of plugin files. 415 * 416 * @param core_plugin_manager $pluginman 417 * @param \core\plugininfo\base $pluginfo 418 * @param progress_trace_buffer $progress 419 * @param moodle_url $continueurl URL to continue to remove the plugin folder 420 * @return string 421 */ 422 public function plugin_uninstall_results_removable_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo, 423 progress_trace_buffer $progress, moodle_url $continueurl) { 424 $output = ''; 425 426 $pluginname = $pluginman->plugin_name($pluginfo->component); 427 428 // Do not show navigation here, they must click one of the buttons. 429 $this->page->set_pagelayout('maintenance'); 430 $this->page->set_cacheable(false); 431 432 $output .= $this->output->header(); 433 $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname))); 434 435 $output .= $this->output->box($progress->get_buffer(), 'generalbox uninstallresultmessage'); 436 437 $confirm = $this->output->container(get_string('uninstalldeleteconfirm', 'core_plugin', 438 array('name' => $pluginname, 'rootdir' => $pluginfo->rootdir)), 'uninstalldeleteconfirm'); 439 440 if ($repotype = $pluginman->plugin_external_source($pluginfo->component)) { 441 $confirm .= $this->output->container(get_string('uninstalldeleteconfirmexternal', 'core_plugin', $repotype), 442 'alert alert-warning mt-2'); 443 } 444 445 // After any uninstall we must execute full upgrade to finish the cleanup! 446 $output .= $this->output->confirm($confirm, $continueurl, new moodle_url('/admin/index.php')); 447 $output .= $this->output->footer(); 448 449 return $output; 450 } 451 452 /** 453 * Display a page with results of plugin uninstallation and inform about the need to remove plugin files manually. 454 * 455 * @param core_plugin_manager $pluginman 456 * @param \core\plugininfo\base $pluginfo 457 * @param progress_trace_buffer $progress 458 * @return string 459 */ 460 public function plugin_uninstall_results_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo, progress_trace_buffer $progress) { 461 $output = ''; 462 463 $pluginname = $pluginfo->component; 464 465 $output .= $this->output->header(); 466 $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname))); 467 468 $output .= $this->output->box($progress->get_buffer(), 'generalbox uninstallresultmessage'); 469 470 $output .= $this->output->box(get_string('uninstalldelete', 'core_plugin', 471 array('name' => $pluginname, 'rootdir' => $pluginfo->rootdir)), 'generalbox uninstalldelete'); 472 $output .= $this->output->continue_button(new moodle_url('/admin/index.php')); 473 $output .= $this->output->footer(); 474 475 return $output; 476 } 477 478 /** 479 * Display the plugin management page (admin/environment.php). 480 * @param array $versions 481 * @param string $version 482 * @param boolean $envstatus final result of env check (true/false) 483 * @param array $environment_results array of results gathered 484 * @return string HTML to output. 485 */ 486 public function environment_check_page($versions, $version, $envstatus, $environment_results) { 487 $output = ''; 488 $output .= $this->header(); 489 490 // Print the component download link 491 $output .= html_writer::tag('div', html_writer::link( 492 new moodle_url('/admin/environment.php', array('action' => 'updatecomponent', 'sesskey' => sesskey())), 493 get_string('updatecomponent', 'admin')), 494 array('class' => 'reportlink')); 495 496 // Heading. 497 $output .= $this->heading(get_string('environment', 'admin')); 498 499 // Box with info and a menu to choose the version. 500 $output .= $this->box_start(); 501 $output .= html_writer::tag('div', get_string('adminhelpenvironment')); 502 $select = new single_select(new moodle_url('/admin/environment.php'), 'version', $versions, $version, null); 503 $select->label = get_string('moodleversion'); 504 $output .= $this->render($select); 505 $output .= $this->box_end(); 506 507 // The results 508 $output .= $this->environment_check_table($envstatus, $environment_results); 509 510 $output .= $this->footer(); 511 return $output; 512 } 513 514 /** 515 * Output a warning message, of the type that appears on the admin notifications page. 516 * @param string $message the message to display. 517 * @param string $type type class 518 * @return string HTML to output. 519 */ 520 protected function warning($message, $type = 'warning') { 521 return $this->box($message, 'generalbox alert alert-' . $type); 522 } 523 524 /** 525 * Render an appropriate message if dataroot is insecure. 526 * @param bool $insecuredataroot 527 * @return string HTML to output. 528 */ 529 protected function insecure_dataroot_warning($insecuredataroot) { 530 global $CFG; 531 532 if ($insecuredataroot == INSECURE_DATAROOT_WARNING) { 533 return $this->warning(get_string('datarootsecuritywarning', 'admin', $CFG->dataroot)); 534 535 } else if ($insecuredataroot == INSECURE_DATAROOT_ERROR) { 536 return $this->warning(get_string('datarootsecurityerror', 'admin', $CFG->dataroot), 'danger'); 537 538 } else { 539 return ''; 540 } 541 } 542 543 /** 544 * Render a warning that a directory with development libs is present. 545 * 546 * @param bool $devlibdir True if the warning should be displayed. 547 * @return string 548 */ 549 protected function development_libs_directories_warning($devlibdir) { 550 551 if ($devlibdir) { 552 $moreinfo = new moodle_url('/report/security/index.php'); 553 $warning = get_string('devlibdirpresent', 'core_admin', ['moreinfourl' => $moreinfo->out()]); 554 return $this->warning($warning, 'danger'); 555 556 } else { 557 return ''; 558 } 559 } 560 561 /** 562 * Render an appropriate message if dataroot is insecure. 563 * @param bool $errorsdisplayed 564 * @return string HTML to output. 565 */ 566 protected function display_errors_warning($errorsdisplayed) { 567 if (!$errorsdisplayed) { 568 return ''; 569 } 570 571 return $this->warning(get_string('displayerrorswarning', 'admin')); 572 } 573 574 /** 575 * Render an appropriate message if themdesignermode is enabled. 576 * @param bool $themedesignermode true if enabled 577 * @return string HTML to output. 578 */ 579 protected function themedesignermode_warning($themedesignermode) { 580 if (!$themedesignermode) { 581 return ''; 582 } 583 584 return $this->warning(get_string('themedesignermodewarning', 'admin')); 585 } 586 587 /** 588 * Render an appropriate message if iconv is buggy and mbstring missing. 589 * @param bool $buggyiconvnomb 590 * @return string HTML to output. 591 */ 592 protected function buggy_iconv_warning($buggyiconvnomb) { 593 if (!$buggyiconvnomb) { 594 return ''; 595 } 596 597 return $this->warning(get_string('warningiconvbuggy', 'admin')); 598 } 599 600 /** 601 * Render an appropriate message if cron has not been run recently. 602 * @param bool $cronoverdue 603 * @return string HTML to output. 604 */ 605 public function cron_overdue_warning($cronoverdue) { 606 global $CFG; 607 if (!$cronoverdue) { 608 return ''; 609 } 610 611 $check = new \tool_task\check\cronrunning(); 612 $result = $check->get_result(); 613 return $this->warning($result->get_summary() . ' ' . $this->help_icon('cron', 'admin')); 614 } 615 616 /** 617 * Render an appropriate message if cron is not being run frequently (recommended every minute). 618 * 619 * @param bool $croninfrequent 620 * @return string HTML to output. 621 */ 622 public function cron_infrequent_warning(bool $croninfrequent) : string { 623 global $CFG; 624 625 if (!$croninfrequent) { 626 return ''; 627 } 628 629 $check = new \tool_task\check\cronrunning(); 630 $result = $check->get_result(); 631 return $this->warning($result->get_summary() . ' ' . $this->help_icon('cron', 'admin')); 632 } 633 634 /** 635 * Render an appropriate message if there are any problems with the DB set-up. 636 * @param bool $dbproblems 637 * @return string HTML to output. 638 */ 639 public function db_problems($dbproblems) { 640 if (!$dbproblems) { 641 return ''; 642 } 643 644 return $this->warning($dbproblems); 645 } 646 647 /** 648 * Renders cache warnings if there are any. 649 * 650 * @param string[] $cachewarnings 651 * @return string 652 */ 653 public function cache_warnings(array $cachewarnings) { 654 if (!count($cachewarnings)) { 655 return ''; 656 } 657 return join("\n", array_map(array($this, 'warning'), $cachewarnings)); 658 } 659 660 /** 661 * Renders events 1 API handlers warning. 662 * 663 * @param array $eventshandlers 664 * @return string 665 */ 666 public function events_handlers($eventshandlers) { 667 if ($eventshandlers) { 668 $components = ''; 669 foreach ($eventshandlers as $eventhandler) { 670 $components .= $eventhandler->component . ', '; 671 } 672 $components = rtrim($components, ', '); 673 return $this->warning(get_string('eventshandlersinuse', 'admin', $components)); 674 } 675 } 676 677 /** 678 * Render an appropriate message if the site in in maintenance mode. 679 * @param bool $maintenancemode 680 * @return string HTML to output. 681 */ 682 public function maintenance_mode_warning($maintenancemode) { 683 if (!$maintenancemode) { 684 return ''; 685 } 686 687 $url = new moodle_url('/admin/settings.php', array('section' => 'maintenancemode')); 688 $url = $url->out(); // get_string() does not support objects in params 689 690 return $this->warning(get_string('sitemaintenancewarning2', 'admin', $url)); 691 } 692 693 /** 694 * Render a warning that ssl is forced because the site was on loginhttps. 695 * 696 * @param bool $overridetossl Whether or not ssl is being forced. 697 * @return string 698 */ 699 protected function overridetossl_warning($overridetossl) { 700 if (!$overridetossl) { 701 return ''; 702 } 703 $warning = get_string('overridetossl', 'core_admin'); 704 return $this->warning($warning, 'warning'); 705 } 706 707 /** 708 * Display a warning about installing development code if necesary. 709 * @param int $maturity 710 * @return string HTML to output. 711 */ 712 protected function maturity_warning($maturity) { 713 if ($maturity == MATURITY_STABLE) { 714 return ''; // No worries. 715 } 716 717 $maturitylevel = get_string('maturity' . $maturity, 'admin'); 718 return $this->warning( 719 $this->container(get_string('maturitycorewarning', 'admin', $maturitylevel)) . 720 $this->container($this->doc_link('admin/versions', get_string('morehelp'))), 721 'danger'); 722 } 723 724 /* 725 * If necessary, displays a warning about upgrading a test site. 726 * 727 * @param string $testsite 728 * @return string HTML 729 */ 730 protected function test_site_warning($testsite) { 731 732 if (!$testsite) { 733 return ''; 734 } 735 736 $warning = (get_string('testsiteupgradewarning', 'admin', $testsite)); 737 return $this->warning($warning, 'danger'); 738 } 739 740 /** 741 * Output the copyright notice. 742 * @return string HTML to output. 743 */ 744 protected function moodle_copyright() { 745 global $CFG; 746 747 ////////////////////////////////////////////////////////////////////////////////////////////////// 748 //// IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE /// 749 $copyrighttext = '<a href="http://moodle.org/">Moodle</a> '. 750 '<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'. 751 'Copyright © 1999 onwards, Martin Dougiamas<br />'. 752 'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'. 753 '<a href="http://docs.moodle.org/dev/License">GNU Public License</a>'; 754 ////////////////////////////////////////////////////////////////////////////////////////////////// 755 756 return $this->box($copyrighttext, 'copyright'); 757 } 758 759 /** 760 * Display a warning about installing development code if necesary. 761 * @param int $maturity 762 * @return string HTML to output. 763 */ 764 protected function maturity_info($maturity) { 765 if ($maturity == MATURITY_STABLE) { 766 return ''; // No worries. 767 } 768 769 $level = 'warning'; 770 771 if ($maturity == MATURITY_ALPHA) { 772 $level = 'danger'; 773 } 774 775 $maturitylevel = get_string('maturity' . $maturity, 'admin'); 776 $warningtext = get_string('maturitycoreinfo', 'admin', $maturitylevel); 777 $warningtext .= ' ' . $this->doc_link('admin/versions', get_string('morehelp')); 778 return $this->warning($warningtext, $level); 779 } 780 781 /** 782 * Displays the info about available Moodle core and plugin updates 783 * 784 * The structure of the $updates param has changed since 2.4. It contains not only updates 785 * for the core itself, but also for all other installed plugins. 786 * 787 * @param array|null $updates array of (string)component => array of \core\update\info objects or null 788 * @param int|null $fetch timestamp of the most recent updates fetch or null (unknown) 789 * @return string 790 */ 791 protected function available_updates($updates, $fetch) { 792 793 $updateinfo = ''; 794 $someupdateavailable = false; 795 if (is_array($updates)) { 796 if (is_array($updates['core'])) { 797 $someupdateavailable = true; 798 $updateinfo .= $this->heading(get_string('updateavailable', 'core_admin'), 3); 799 foreach ($updates['core'] as $update) { 800 $updateinfo .= $this->moodle_available_update_info($update); 801 } 802 $updateinfo .= html_writer::tag('p', get_string('updateavailablerecommendation', 'core_admin'), 803 array('class' => 'updateavailablerecommendation')); 804 } 805 unset($updates['core']); 806 // If something has left in the $updates array now, it is updates for plugins. 807 if (!empty($updates)) { 808 $someupdateavailable = true; 809 $updateinfo .= $this->heading(get_string('updateavailableforplugin', 'core_admin'), 3); 810 $pluginsoverviewurl = new moodle_url('/admin/plugins.php', array('updatesonly' => 1)); 811 $updateinfo .= $this->container(get_string('pluginsoverviewsee', 'core_admin', 812 array('url' => $pluginsoverviewurl->out()))); 813 } 814 } 815 816 if (!$someupdateavailable) { 817 $now = time(); 818 if ($fetch and ($fetch <= $now) and ($now - $fetch < HOURSECS)) { 819 $updateinfo .= $this->heading(get_string('updateavailablenot', 'core_admin'), 3); 820 } 821 } 822 823 $updateinfo .= $this->container_start('checkforupdates mt-1'); 824 $fetchurl = new moodle_url('/admin/index.php', array('fetchupdates' => 1, 'sesskey' => sesskey(), 'cache' => 0)); 825 $updateinfo .= $this->single_button($fetchurl, get_string('checkforupdates', 'core_plugin')); 826 if ($fetch) { 827 $updateinfo .= $this->container(get_string('checkforupdateslast', 'core_plugin', 828 userdate($fetch, get_string('strftimedatetime', 'core_langconfig')))); 829 } 830 $updateinfo .= $this->container_end(); 831 832 return $this->warning($updateinfo); 833 } 834 835 /** 836 * Display a warning about not being registered on Moodle.org if necesary. 837 * 838 * @param boolean $registered true if the site is registered on Moodle.org 839 * @return string HTML to output. 840 */ 841 protected function registration_warning($registered) { 842 843 if (!$registered && site_is_public()) { 844 if (has_capability('moodle/site:config', context_system::instance())) { 845 $registerbutton = $this->single_button(new moodle_url('/admin/registration/index.php'), 846 get_string('register', 'admin')); 847 $str = 'registrationwarning'; 848 } else { 849 $registerbutton = ''; 850 $str = 'registrationwarningcontactadmin'; 851 } 852 853 return $this->warning( get_string($str, 'admin') 854 . ' ' . $this->help_icon('registration', 'admin') . $registerbutton , 855 'error alert alert-danger'); 856 } 857 858 return ''; 859 } 860 861 /** 862 * Return an admin page warning if site is not registered with moodle.org 863 * 864 * @return string 865 */ 866 public function warn_if_not_registered() { 867 return $this->registration_warning(\core\hub\registration::is_registered()); 868 } 869 870 /** 871 * Display a warning about the Mobile Web Services being disabled. 872 * 873 * @param boolean $mobileconfigured true if mobile web services are enabled 874 * @return string HTML to output. 875 */ 876 protected function mobile_configuration_warning($mobileconfigured) { 877 $output = ''; 878 if (!$mobileconfigured) { 879 $settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']); 880 $configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin')); 881 $output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . ' ' . $configurebutton); 882 } 883 884 return $output; 885 } 886 887 /** 888 * Display campaign content. 889 * 890 * @param bool $showcampaigncontent Whether the campaign content should be visible or not. 891 * @return string the campaign content raw html. 892 */ 893 protected function campaign_content(bool $showcampaigncontent): string { 894 if (!$showcampaigncontent) { 895 return ''; 896 } 897 898 return $this->render_from_template('core/campaign_content', ['lang' => current_language()]); 899 } 900 901 /** 902 * Display a warning about the forgotten password URL not linking to a valid URL. 903 * 904 * @param boolean $invalidforgottenpasswordurl true if the forgotten password URL is not valid 905 * @return string HTML to output. 906 */ 907 protected function forgotten_password_url_warning($invalidforgottenpasswordurl) { 908 $output = ''; 909 if ($invalidforgottenpasswordurl) { 910 $settingslink = new moodle_url('/admin/settings.php', ['section' => 'manageauths']); 911 $configurebutton = $this->single_button($settingslink, get_string('check', 'moodle')); 912 $output .= $this->warning(get_string('invalidforgottenpasswordurl', 'admin') . ' ' . $configurebutton, 913 'error alert alert-danger'); 914 } 915 916 return $output; 917 } 918 919 /** 920 * Helper method to render the information about the available Moodle update 921 * 922 * @param \core\update\info $updateinfo information about the available Moodle core update 923 */ 924 protected function moodle_available_update_info(\core\update\info $updateinfo) { 925 926 $boxclasses = 'moodleupdateinfo mb-2'; 927 $info = array(); 928 929 if (isset($updateinfo->release)) { 930 $info[] = html_writer::tag('span', get_string('updateavailable_release', 'core_admin', $updateinfo->release), 931 array('class' => 'info release')); 932 } 933 934 if (isset($updateinfo->version)) { 935 $info[] = html_writer::tag('span', get_string('updateavailable_version', 'core_admin', $updateinfo->version), 936 array('class' => 'info version')); 937 } 938 939 if (isset($updateinfo->maturity)) { 940 $info[] = html_writer::tag('span', get_string('maturity'.$updateinfo->maturity, 'core_admin'), 941 array('class' => 'info maturity')); 942 $boxclasses .= ' maturity'.$updateinfo->maturity; 943 } 944 945 if (isset($updateinfo->download)) { 946 $info[] = html_writer::link($updateinfo->download, get_string('download'), 947 array('class' => 'info download btn btn-secondary')); 948 } 949 950 if (isset($updateinfo->url)) { 951 $info[] = html_writer::link($updateinfo->url, get_string('updateavailable_moreinfo', 'core_plugin'), 952 array('class' => 'info more')); 953 } 954 955 $box = $this->output->container_start($boxclasses); 956 $box .= $this->output->container(implode(html_writer::tag('span', ' | ', array('class' => 'separator')), $info), ''); 957 $box .= $this->output->container_end(); 958 959 return $box; 960 } 961 962 /** 963 * Display a link to the release notes. 964 * @return string HTML to output. 965 */ 966 protected function release_notes_link() { 967 $releasenoteslink = get_string('releasenoteslink', 'admin', 'http://docs.moodle.org/dev/Releases'); 968 $releasenoteslink = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $releasenoteslink); // extremely ugly validation hack 969 return $this->box($releasenoteslink, 'generalbox alert alert-info'); 970 } 971 972 /** 973 * Display the reload link that appears on several upgrade/install pages. 974 * @return string HTML to output. 975 */ 976 function upgrade_reload($url) { 977 return html_writer::empty_tag('br') . 978 html_writer::tag('div', 979 html_writer::link($url, $this->pix_icon('i/reload', '', '', array('class' => 'icon icon-pre')) . 980 get_string('reload'), array('title' => get_string('reload'))), 981 array('class' => 'continuebutton')) . html_writer::empty_tag('br'); 982 } 983 984 /** 985 * Displays all known plugins and information about their installation or upgrade 986 * 987 * This default implementation renders all plugins into one big table. The rendering 988 * options support: 989 * (bool)full = false: whether to display up-to-date plugins, too 990 * (bool)xdep = false: display the plugins with unsatisified dependecies only 991 * 992 * @param core_plugin_manager $pluginman provides information about the plugins. 993 * @param int $version the version of the Moodle code from version.php. 994 * @param array $options rendering options 995 * @return string HTML code 996 */ 997 public function plugins_check_table(core_plugin_manager $pluginman, $version, array $options = array()) { 998 global $CFG; 999 $plugininfo = $pluginman->get_plugins(); 1000 1001 if (empty($plugininfo)) { 1002 return ''; 1003 } 1004 1005 $options['full'] = isset($options['full']) ? (bool)$options['full'] : false; 1006 $options['xdep'] = isset($options['xdep']) ? (bool)$options['xdep'] : false; 1007 1008 $table = new html_table(); 1009 $table->id = 'plugins-check'; 1010 $table->head = array( 1011 get_string('displayname', 'core_plugin').' / '.get_string('rootdir', 'core_plugin'), 1012 get_string('versiondb', 'core_plugin'), 1013 get_string('versiondisk', 'core_plugin'), 1014 get_string('requires', 'core_plugin'), 1015 get_string('source', 'core_plugin').' / '.get_string('status', 'core_plugin'), 1016 ); 1017 $table->colclasses = array( 1018 'displayname', 'versiondb', 'versiondisk', 'requires', 'status', 1019 ); 1020 $table->data = array(); 1021 1022 // Number of displayed plugins per type. 1023 $numdisplayed = array(); 1024 // Number of plugins known to the plugin manager. 1025 $sumtotal = 0; 1026 // Number of plugins requiring attention. 1027 $sumattention = 0; 1028 // List of all components we can cancel installation of. 1029 $installabortable = $pluginman->list_cancellable_installations(); 1030 // List of all components we can cancel upgrade of. 1031 $upgradeabortable = $pluginman->list_restorable_archives(); 1032 1033 foreach ($plugininfo as $type => $plugins) { 1034 1035 $header = new html_table_cell($pluginman->plugintype_name_plural($type)); 1036 $header->header = true; 1037 $header->colspan = count($table->head); 1038 $header = new html_table_row(array($header)); 1039 $header->attributes['class'] = 'plugintypeheader type-' . $type; 1040 1041 $numdisplayed[$type] = 0; 1042 1043 if (empty($plugins) and $options['full']) { 1044 $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin')); 1045 $msg->colspan = count($table->head); 1046 $row = new html_table_row(array($msg)); 1047 $row->attributes['class'] .= 'msg msg-noneinstalled'; 1048 $table->data[] = $header; 1049 $table->data[] = $row; 1050 continue; 1051 } 1052 1053 $plugintyperows = array(); 1054 1055 foreach ($plugins as $name => $plugin) { 1056 $sumtotal++; 1057 $row = new html_table_row(); 1058 $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name; 1059 1060 if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name, null)) { 1061 $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon')); 1062 } else { 1063 $icon = ''; 1064 } 1065 1066 $displayname = new html_table_cell( 1067 $icon. 1068 html_writer::span($plugin->displayname, 'pluginname'). 1069 html_writer::div($plugin->get_dir(), 'plugindir text-muted small') 1070 ); 1071 1072 $versiondb = new html_table_cell($plugin->versiondb); 1073 $versiondisk = new html_table_cell($plugin->versiondisk); 1074 1075 if ($isstandard = $plugin->is_standard()) { 1076 $row->attributes['class'] .= ' standard'; 1077 $sourcelabel = html_writer::span(get_string('sourcestd', 'core_plugin'), 'sourcetext badge badge-secondary'); 1078 } else { 1079 $row->attributes['class'] .= ' extension'; 1080 $sourcelabel = html_writer::span(get_string('sourceext', 'core_plugin'), 'sourcetext badge badge-info'); 1081 } 1082 1083 $coredependency = $plugin->is_core_dependency_satisfied($version); 1084 $incompatibledependency = $plugin->is_core_compatible_satisfied($CFG->branch); 1085 1086 $otherpluginsdependencies = $pluginman->are_dependencies_satisfied($plugin->get_other_required_plugins()); 1087 $dependenciesok = $coredependency && $otherpluginsdependencies && $incompatibledependency; 1088 1089 $statuscode = $plugin->get_status(); 1090 $row->attributes['class'] .= ' status-' . $statuscode; 1091 $statusclass = 'statustext badge '; 1092 switch ($statuscode) { 1093 case core_plugin_manager::PLUGIN_STATUS_NEW: 1094 $statusclass .= $dependenciesok ? 'badge-success' : 'badge-warning'; 1095 break; 1096 case core_plugin_manager::PLUGIN_STATUS_UPGRADE: 1097 $statusclass .= $dependenciesok ? 'badge-info' : 'badge-warning'; 1098 break; 1099 case core_plugin_manager::PLUGIN_STATUS_MISSING: 1100 case core_plugin_manager::PLUGIN_STATUS_DOWNGRADE: 1101 case core_plugin_manager::PLUGIN_STATUS_DELETE: 1102 $statusclass .= 'badge-danger'; 1103 break; 1104 case core_plugin_manager::PLUGIN_STATUS_NODB: 1105 case core_plugin_manager::PLUGIN_STATUS_UPTODATE: 1106 $statusclass .= $dependenciesok ? 'badge-light' : 'badge-warning'; 1107 break; 1108 } 1109 $status = html_writer::span(get_string('status_' . $statuscode, 'core_plugin'), $statusclass); 1110 1111 if (!empty($installabortable[$plugin->component])) { 1112 $status .= $this->output->single_button( 1113 new moodle_url($this->page->url, array('abortinstall' => $plugin->component, 'confirmplugincheck' => 0)), 1114 get_string('cancelinstallone', 'core_plugin'), 1115 'post', 1116 array('class' => 'actionbutton cancelinstallone d-block mt-1') 1117 ); 1118 } 1119 1120 if (!empty($upgradeabortable[$plugin->component])) { 1121 $status .= $this->output->single_button( 1122 new moodle_url($this->page->url, array('abortupgrade' => $plugin->component)), 1123 get_string('cancelupgradeone', 'core_plugin'), 1124 'post', 1125 array('class' => 'actionbutton cancelupgradeone d-block mt-1') 1126 ); 1127 } 1128 1129 $availableupdates = $plugin->available_updates(); 1130 if (!empty($availableupdates)) { 1131 foreach ($availableupdates as $availableupdate) { 1132 $status .= $this->plugin_available_update_info($pluginman, $availableupdate); 1133 } 1134 } 1135 1136 $status = new html_table_cell($sourcelabel.' '.$status); 1137 if ($plugin->pluginsupported != null) { 1138 $requires = new html_table_cell($this->required_column($plugin, $pluginman, $version, $CFG->branch)); 1139 } else { 1140 $requires = new html_table_cell($this->required_column($plugin, $pluginman, $version)); 1141 } 1142 1143 $statusisboring = in_array($statuscode, array( 1144 core_plugin_manager::PLUGIN_STATUS_NODB, core_plugin_manager::PLUGIN_STATUS_UPTODATE)); 1145 1146 if ($options['xdep']) { 1147 // we want to see only plugins with failed dependencies 1148 if ($dependenciesok) { 1149 continue; 1150 } 1151 1152 } else if ($statusisboring and $dependenciesok and empty($availableupdates)) { 1153 // no change is going to happen to the plugin - display it only 1154 // if the user wants to see the full list 1155 if (empty($options['full'])) { 1156 continue; 1157 } 1158 1159 } else { 1160 $sumattention++; 1161 } 1162 1163 // The plugin should be displayed. 1164 $numdisplayed[$type]++; 1165 $row->cells = array($displayname, $versiondb, $versiondisk, $requires, $status); 1166 $plugintyperows[] = $row; 1167 } 1168 1169 if (empty($numdisplayed[$type]) and empty($options['full'])) { 1170 continue; 1171 } 1172 1173 $table->data[] = $header; 1174 $table->data = array_merge($table->data, $plugintyperows); 1175 } 1176 1177 // Total number of displayed plugins. 1178 $sumdisplayed = array_sum($numdisplayed); 1179 1180 if ($options['xdep']) { 1181 // At the plugins dependencies check page, display the table only. 1182 return html_writer::table($table); 1183 } 1184 1185 $out = $this->output->container_start('', 'plugins-check-info'); 1186 1187 if ($sumdisplayed == 0) { 1188 $out .= $this->output->heading(get_string('pluginchecknone', 'core_plugin')); 1189 1190 } else { 1191 if (empty($options['full'])) { 1192 $out .= $this->output->heading(get_string('plugincheckattention', 'core_plugin')); 1193 } else { 1194 $out .= $this->output->heading(get_string('plugincheckall', 'core_plugin')); 1195 } 1196 } 1197 1198 $out .= $this->output->container_start('actions mb-2'); 1199 1200 $installableupdates = $pluginman->filter_installable($pluginman->available_updates()); 1201 if ($installableupdates) { 1202 $out .= $this->output->single_button( 1203 new moodle_url($this->page->url, array('installupdatex' => 1)), 1204 get_string('updateavailableinstallall', 'core_admin', count($installableupdates)), 1205 'post', 1206 array('class' => 'singlebutton updateavailableinstallall mr-1') 1207 ); 1208 } 1209 1210 if ($installabortable) { 1211 $out .= $this->output->single_button( 1212 new moodle_url($this->page->url, array('abortinstallx' => 1, 'confirmplugincheck' => 0)), 1213 get_string('cancelinstallall', 'core_plugin', count($installabortable)), 1214 'post', 1215 array('class' => 'singlebutton cancelinstallall mr-1') 1216 ); 1217 } 1218 1219 if ($upgradeabortable) { 1220 $out .= $this->output->single_button( 1221 new moodle_url($this->page->url, array('abortupgradex' => 1)), 1222 get_string('cancelupgradeall', 'core_plugin', count($upgradeabortable)), 1223 'post', 1224 array('class' => 'singlebutton cancelupgradeall mr-1') 1225 ); 1226 } 1227 1228 $out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 0)), 1229 get_string('plugincheckattention', 'core_plugin')).' '.html_writer::span($sumattention, 'badge badge-light'), 1230 'btn btn-link mr-1'); 1231 1232 $out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 1)), 1233 get_string('plugincheckall', 'core_plugin')).' '.html_writer::span($sumtotal, 'badge badge-light'), 1234 'btn btn-link mr-1'); 1235 1236 $out .= $this->output->container_end(); // End of .actions container. 1237 $out .= $this->output->container_end(); // End of #plugins-check-info container. 1238 1239 if ($sumdisplayed > 0 or $options['full']) { 1240 $out .= html_writer::table($table); 1241 } 1242 1243 return $out; 1244 } 1245 1246 /** 1247 * Display the continue / cancel widgets for the plugins management pages. 1248 * 1249 * @param null|moodle_url $continue URL for the continue button, should it be displayed 1250 * @param null|moodle_url $cancel URL for the cancel link, defaults to the current page 1251 * @return string HTML 1252 */ 1253 public function plugins_management_confirm_buttons(moodle_url $continue=null, moodle_url $cancel=null) { 1254 1255 $out = html_writer::start_div('plugins-management-confirm-buttons'); 1256 1257 if (!empty($continue)) { 1258 $out .= $this->output->single_button($continue, get_string('continue'), 'post', array('class' => 'continue')); 1259 } 1260 1261 if (empty($cancel)) { 1262 $cancel = $this->page->url; 1263 } 1264 $out .= html_writer::div(html_writer::link($cancel, get_string('cancel')), 'cancel'); 1265 1266 return $out; 1267 } 1268 1269 /** 1270 * Displays the information about missing dependencies 1271 * 1272 * @param core_plugin_manager $pluginman 1273 * @return string 1274 */ 1275 protected function missing_dependencies(core_plugin_manager $pluginman) { 1276 1277 $dependencies = $pluginman->missing_dependencies(); 1278 1279 if (empty($dependencies)) { 1280 return ''; 1281 } 1282 1283 $available = array(); 1284 $unavailable = array(); 1285 $unknown = array(); 1286 1287 foreach ($dependencies as $component => $remoteinfo) { 1288 if ($remoteinfo === false) { 1289 // The required version is not available. Let us check if there 1290 // is at least some version in the plugins directory. 1291 $remoteinfoanyversion = $pluginman->get_remote_plugin_info($component, ANY_VERSION, false); 1292 if ($remoteinfoanyversion === false) { 1293 $unknown[$component] = $component; 1294 } else { 1295 $unavailable[$component] = $remoteinfoanyversion; 1296 } 1297 } else { 1298 $available[$component] = $remoteinfo; 1299 } 1300 } 1301 1302 $out = $this->output->container_start('plugins-check-dependencies mb-4'); 1303 1304 if ($unavailable or $unknown) { 1305 $out .= $this->output->heading(get_string('misdepsunavail', 'core_plugin')); 1306 if ($unknown) { 1307 $out .= $this->output->render((new \core\output\notification(get_string('misdepsunknownlist', 'core_plugin', 1308 implode(', ', $unknown))))->set_show_closebutton(false)); 1309 } 1310 if ($unavailable) { 1311 $unavailablelist = array(); 1312 foreach ($unavailable as $component => $remoteinfoanyversion) { 1313 $unavailablelistitem = html_writer::link('https://moodle.org/plugins/view.php?plugin='.$component, 1314 '<strong>'.$remoteinfoanyversion->name.'</strong>'); 1315 if ($remoteinfoanyversion->version) { 1316 $unavailablelistitem .= ' ('.$component.' > '.$remoteinfoanyversion->version->version.')'; 1317 } else { 1318 $unavailablelistitem .= ' ('.$component.')'; 1319 } 1320 $unavailablelist[] = $unavailablelistitem; 1321 } 1322 $out .= $this->output->render((new \core\output\notification(get_string('misdepsunavaillist', 'core_plugin', 1323 implode(', ', $unavailablelist))))->set_show_closebutton(false)); 1324 } 1325 $out .= $this->output->container_start('plugins-check-dependencies-actions mb-4'); 1326 $out .= ' '.html_writer::link(new moodle_url('/admin/tool/installaddon/'), 1327 get_string('dependencyuploadmissing', 'core_plugin'), array('class' => 'btn btn-secondary')); 1328 $out .= $this->output->container_end(); // End of .plugins-check-dependencies-actions container. 1329 } 1330 1331 if ($available) { 1332 $out .= $this->output->heading(get_string('misdepsavail', 'core_plugin')); 1333 $out .= $this->output->container_start('plugins-check-dependencies-actions mb-2'); 1334 1335 $installable = $pluginman->filter_installable($available); 1336 if ($installable) { 1337 $out .= $this->output->single_button( 1338 new moodle_url($this->page->url, array('installdepx' => 1)), 1339 get_string('dependencyinstallmissing', 'core_plugin', count($installable)), 1340 'post', 1341 array('class' => 'singlebutton dependencyinstallmissing d-inline-block mr-1') 1342 ); 1343 } 1344 1345 $out .= html_writer::div(html_writer::link(new moodle_url('/admin/tool/installaddon/'), 1346 get_string('dependencyuploadmissing', 'core_plugin'), array('class' => 'btn btn-link')), 1347 'dependencyuploadmissing d-inline-block mr-1'); 1348 1349 $out .= $this->output->container_end(); // End of .plugins-check-dependencies-actions container. 1350 1351 $out .= $this->available_missing_dependencies_list($pluginman, $available); 1352 } 1353 1354 $out .= $this->output->container_end(); // End of .plugins-check-dependencies container. 1355 1356 return $out; 1357 } 1358 1359 /** 1360 * Displays the list if available missing dependencies. 1361 * 1362 * @param core_plugin_manager $pluginman 1363 * @param array $dependencies 1364 * @return string 1365 */ 1366 protected function available_missing_dependencies_list(core_plugin_manager $pluginman, array $dependencies) { 1367 global $CFG; 1368 1369 $table = new html_table(); 1370 $table->id = 'plugins-check-available-dependencies'; 1371 $table->head = array( 1372 get_string('displayname', 'core_plugin'), 1373 get_string('release', 'core_plugin'), 1374 get_string('version', 'core_plugin'), 1375 get_string('supportedmoodleversions', 'core_plugin'), 1376 get_string('info', 'core'), 1377 ); 1378 $table->colclasses = array('displayname', 'release', 'version', 'supportedmoodleversions', 'info'); 1379 $table->data = array(); 1380 1381 foreach ($dependencies as $plugin) { 1382 1383 $supportedmoodles = array(); 1384 foreach ($plugin->version->supportedmoodles as $moodle) { 1385 if ($CFG->branch == str_replace('.', '', $moodle->release)) { 1386 $supportedmoodles[] = html_writer::span($moodle->release, 'badge badge-success'); 1387 } else { 1388 $supportedmoodles[] = html_writer::span($moodle->release, 'badge badge-light'); 1389 } 1390 } 1391 1392 $requriedby = $pluginman->other_plugins_that_require($plugin->component); 1393 if ($requriedby) { 1394 foreach ($requriedby as $ix => $val) { 1395 $inf = $pluginman->get_plugin_info($val); 1396 if ($inf) { 1397 $requriedby[$ix] = $inf->displayname.' ('.$inf->component.')'; 1398 } 1399 } 1400 $info = html_writer::div( 1401 get_string('requiredby', 'core_plugin', implode(', ', $requriedby)), 1402 'requiredby mb-1' 1403 ); 1404 } else { 1405 $info = ''; 1406 } 1407 1408 $info .= $this->output->container_start('actions'); 1409 1410 $info .= html_writer::div( 1411 html_writer::link('https://moodle.org/plugins/view.php?plugin='.$plugin->component, 1412 get_string('misdepinfoplugin', 'core_plugin')), 1413 'misdepinfoplugin d-inline-block mr-3 mb-1' 1414 ); 1415 1416 $info .= html_writer::div( 1417 html_writer::link('https://moodle.org/plugins/pluginversion.php?id='.$plugin->version->id, 1418 get_string('misdepinfoversion', 'core_plugin')), 1419 'misdepinfoversion d-inline-block mr-3 mb-1' 1420 ); 1421 1422 $info .= html_writer::div(html_writer::link($plugin->version->downloadurl, get_string('download')), 1423 'misdepdownload d-inline-block mr-3 mb-1'); 1424 1425 if ($pluginman->is_remote_plugin_installable($plugin->component, $plugin->version->version, $reason)) { 1426 $info .= $this->output->single_button( 1427 new moodle_url($this->page->url, array('installdep' => $plugin->component)), 1428 get_string('dependencyinstall', 'core_plugin'), 1429 'post', 1430 array('class' => 'singlebutton dependencyinstall mr-3 mb-1') 1431 ); 1432 } else { 1433 $reasonhelp = $this->info_remote_plugin_not_installable($reason); 1434 if ($reasonhelp) { 1435 $info .= html_writer::div($reasonhelp, 'reasonhelp dependencyinstall d-inline-block mr-3 mb-1'); 1436 } 1437 } 1438 1439 $info .= $this->output->container_end(); // End of .actions container. 1440 1441 $table->data[] = array( 1442 html_writer::div($plugin->name, 'name').' '.html_writer::div($plugin->component, 'component text-muted small'), 1443 $plugin->version->release, 1444 $plugin->version->version, 1445 implode(' ', $supportedmoodles), 1446 $info 1447 ); 1448 } 1449 1450 return html_writer::table($table); 1451 } 1452 1453 /** 1454 * Explain why {@link core_plugin_manager::is_remote_plugin_installable()} returned false. 1455 * 1456 * @param string $reason the reason code as returned by the plugin manager 1457 * @return string 1458 */ 1459 protected function info_remote_plugin_not_installable($reason) { 1460 1461 if ($reason === 'notwritableplugintype' or $reason === 'notwritableplugin') { 1462 return $this->output->help_icon('notwritable', 'core_plugin', get_string('notwritable', 'core_plugin')); 1463 } 1464 1465 if ($reason === 'remoteunavailable') { 1466 return $this->output->help_icon('notdownloadable', 'core_plugin', get_string('notdownloadable', 'core_plugin')); 1467 } 1468 1469 return false; 1470 } 1471 1472 /** 1473 * Formats the information that needs to go in the 'Requires' column. 1474 * @param \core\plugininfo\base $plugin the plugin we are rendering the row for. 1475 * @param core_plugin_manager $pluginman provides data on all the plugins. 1476 * @param string $version 1477 * @param int $branch the current Moodle branch 1478 * @return string HTML code 1479 */ 1480 protected function required_column(\core\plugininfo\base $plugin, core_plugin_manager $pluginman, $version, $branch = null) { 1481 1482 $requires = array(); 1483 $displayuploadlink = false; 1484 $displayupdateslink = false; 1485 1486 $requirements = $pluginman->resolve_requirements($plugin, $version, $branch); 1487 foreach ($requirements as $reqname => $reqinfo) { 1488 if ($reqname === 'core') { 1489 if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OK) { 1490 $class = 'requires-ok text-muted'; 1491 $label = ''; 1492 } else { 1493 $class = 'requires-failed'; 1494 $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-danger'); 1495 } 1496 1497 if ($branch != null && !$plugin->is_core_compatible_satisfied($branch)) { 1498 $requires[] = html_writer::tag('li', 1499 html_writer::span(get_string('incompatibleversion', 'core_plugin', $branch), 'dep dep-core'). 1500 ' '.$label, array('class' => $class)); 1501 1502 } else if ($branch != null && $plugin->pluginsupported != null) { 1503 $requires[] = html_writer::tag('li', 1504 html_writer::span(get_string('moodlebranch', 'core_plugin', 1505 array('min' => $plugin->pluginsupported[0], 'max' => $plugin->pluginsupported[1])), 'dep dep-core'). 1506 ' '.$label, array('class' => $class)); 1507 1508 } else if ($reqinfo->reqver != ANY_VERSION) { 1509 $requires[] = html_writer::tag('li', 1510 html_writer::span(get_string('moodleversion', 'core_plugin', $plugin->versionrequires), 'dep dep-core'). 1511 ' '.$label, array('class' => $class)); 1512 } 1513 1514 } else { 1515 $actions = array(); 1516 1517 if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OK) { 1518 $label = ''; 1519 $class = 'requires-ok text-muted'; 1520 1521 } else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_MISSING) { 1522 if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) { 1523 $label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge badge-warning'); 1524 $label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'badge badge-warning'); 1525 $class = 'requires-failed requires-missing requires-available'; 1526 $actions[] = html_writer::link( 1527 new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $reqname)), 1528 get_string('misdepinfoplugin', 'core_plugin') 1529 ); 1530 1531 } else { 1532 $label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge badge-danger'); 1533 $label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'), 1534 'badge badge-danger'); 1535 $class = 'requires-failed requires-missing requires-unavailable'; 1536 } 1537 $displayuploadlink = true; 1538 1539 } else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OUTDATED) { 1540 if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) { 1541 $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-warning'); 1542 $label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'badge badge-warning'); 1543 $class = 'requires-failed requires-outdated requires-available'; 1544 $displayupdateslink = true; 1545 1546 } else { 1547 $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-danger'); 1548 $label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'), 1549 'badge badge-danger'); 1550 $class = 'requires-failed requires-outdated requires-unavailable'; 1551 } 1552 $displayuploadlink = true; 1553 } 1554 1555 if ($reqinfo->reqver != ANY_VERSION) { 1556 $str = 'otherpluginversion'; 1557 } else { 1558 $str = 'otherplugin'; 1559 } 1560 1561 $requires[] = html_writer::tag('li', html_writer::span( 1562 get_string($str, 'core_plugin', array('component' => $reqname, 'version' => $reqinfo->reqver)), 1563 'dep dep-plugin').' '.$label.' '.html_writer::span(implode(' | ', $actions), 'actions'), 1564 array('class' => $class) 1565 ); 1566 } 1567 } 1568 1569 if (!$requires) { 1570 return ''; 1571 } 1572 1573 $out = html_writer::tag('ul', implode("\n", $requires), array('class' => 'm-0')); 1574 1575 if ($displayuploadlink) { 1576 $out .= html_writer::div( 1577 html_writer::link( 1578 new moodle_url('/admin/tool/installaddon/'), 1579 get_string('dependencyuploadmissing', 'core_plugin'), 1580 array('class' => 'btn btn-secondary btn-sm m-1') 1581 ), 1582 'dependencyuploadmissing' 1583 ); 1584 } 1585 1586 if ($displayupdateslink) { 1587 $out .= html_writer::div( 1588 html_writer::link( 1589 new moodle_url($this->page->url, array('sesskey' => sesskey(), 'fetchupdates' => 1)), 1590 get_string('checkforupdates', 'core_plugin'), 1591 array('class' => 'btn btn-secondary btn-sm m-1') 1592 ), 1593 'checkforupdates' 1594 ); 1595 } 1596 1597 // Check if supports is present, and $branch is not in, only if $incompatible check was ok. 1598 if ($plugin->pluginsupported != null && $class == 'requires-ok' && $branch != null) { 1599 if ($pluginman->check_explicitly_supported($plugin, $branch) == $pluginman::VERSION_NOT_SUPPORTED) { 1600 $out .= html_writer::div(get_string('notsupported', 'core_plugin', $branch)); 1601 } 1602 } 1603 1604 return $out; 1605 1606 } 1607 1608 /** 1609 * Prints an overview about the plugins - number of installed, number of extensions etc. 1610 * 1611 * @param core_plugin_manager $pluginman provides information about the plugins 1612 * @param array $options filtering options 1613 * @return string as usually 1614 */ 1615 public function plugins_overview_panel(core_plugin_manager $pluginman, array $options = array()) { 1616 1617 $plugininfo = $pluginman->get_plugins(); 1618 1619 $numtotal = $numextension = $numupdatable = $numinstallable = 0; 1620 1621 foreach ($plugininfo as $type => $plugins) { 1622 foreach ($plugins as $name => $plugin) { 1623 if ($res = $plugin->available_updates()) { 1624 $numupdatable++; 1625 foreach ($res as $updateinfo) { 1626 if ($pluginman->is_remote_plugin_installable($updateinfo->component, $updateinfo->version, $reason, false)) { 1627 $numinstallable++; 1628 break; 1629 } 1630 } 1631 } 1632 if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) { 1633 continue; 1634 } 1635 $numtotal++; 1636 if (!$plugin->is_standard()) { 1637 $numextension++; 1638 } 1639 } 1640 } 1641 1642 $infoall = html_writer::link( 1643 new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 0)), 1644 get_string('overviewall', 'core_plugin'), 1645 array('title' => get_string('filterall', 'core_plugin')) 1646 ).' '.html_writer::span($numtotal, 'badge number number-all'); 1647 1648 $infoext = html_writer::link( 1649 new moodle_url($this->page->url, array('contribonly' => 1, 'updatesonly' => 0)), 1650 get_string('overviewext', 'core_plugin'), 1651 array('title' => get_string('filtercontribonly', 'core_plugin')) 1652 ).' '.html_writer::span($numextension, 'badge number number-additional'); 1653 1654 if ($numupdatable) { 1655 $infoupdatable = html_writer::link( 1656 new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 1)), 1657 get_string('overviewupdatable', 'core_plugin'), 1658 array('title' => get_string('filterupdatesonly', 'core_plugin')) 1659 ).' '.html_writer::span($numupdatable, 'badge badge-info number number-updatable'); 1660 } else { 1661 // No updates, or the notifications disabled. 1662 $infoupdatable = ''; 1663 } 1664 1665 $out = html_writer::start_div('', array('id' => 'plugins-overview-panel')); 1666 1667 if (!empty($options['updatesonly'])) { 1668 $out .= $this->output->heading(get_string('overviewupdatable', 'core_plugin'), 3); 1669 } else if (!empty($options['contribonly'])) { 1670 $out .= $this->output->heading(get_string('overviewext', 'core_plugin'), 3); 1671 } 1672 1673 if ($numinstallable) { 1674 $out .= $this->output->single_button( 1675 new moodle_url($this->page->url, array('installupdatex' => 1)), 1676 get_string('updateavailableinstallall', 'core_admin', $numinstallable), 1677 'post', 1678 array('class' => 'singlebutton updateavailableinstallall') 1679 ); 1680 } 1681 1682 $out .= html_writer::div($infoall, 'info info-all'). 1683 html_writer::div($infoext, 'info info-ext'). 1684 html_writer::div($infoupdatable, 'info info-updatable'); 1685 1686 $out .= html_writer::end_div(); // End of #plugins-overview-panel block. 1687 1688 return $out; 1689 } 1690 1691 /** 1692 * Displays all known plugins and links to manage them 1693 * 1694 * This default implementation renders all plugins into one big table. 1695 * 1696 * @param core_plugin_manager $pluginman provides information about the plugins. 1697 * @param array $options filtering options 1698 * @return string HTML code 1699 */ 1700 public function plugins_control_panel(core_plugin_manager $pluginman, array $options = array()) { 1701 1702 $plugininfo = $pluginman->get_plugins(); 1703 1704 // Filter the list of plugins according the options. 1705 if (!empty($options['updatesonly'])) { 1706 $updateable = array(); 1707 foreach ($plugininfo as $plugintype => $pluginnames) { 1708 foreach ($pluginnames as $pluginname => $pluginfo) { 1709 $pluginavailableupdates = $pluginfo->available_updates(); 1710 if (!empty($pluginavailableupdates)) { 1711 foreach ($pluginavailableupdates as $pluginavailableupdate) { 1712 $updateable[$plugintype][$pluginname] = $pluginfo; 1713 } 1714 } 1715 } 1716 } 1717 $plugininfo = $updateable; 1718 } 1719 1720 if (!empty($options['contribonly'])) { 1721 $contribs = array(); 1722 foreach ($plugininfo as $plugintype => $pluginnames) { 1723 foreach ($pluginnames as $pluginname => $pluginfo) { 1724 if (!$pluginfo->is_standard()) { 1725 $contribs[$plugintype][$pluginname] = $pluginfo; 1726 } 1727 } 1728 } 1729 $plugininfo = $contribs; 1730 } 1731 1732 if (empty($plugininfo)) { 1733 return ''; 1734 } 1735 1736 $table = new html_table(); 1737 $table->id = 'plugins-control-panel'; 1738 $table->head = array( 1739 get_string('displayname', 'core_plugin'), 1740 get_string('version', 'core_plugin'), 1741 get_string('availability', 'core_plugin'), 1742 get_string('actions', 'core_plugin'), 1743 get_string('notes','core_plugin'), 1744 ); 1745 $table->headspan = array(1, 1, 1, 2, 1); 1746 $table->colclasses = array( 1747 'pluginname', 'version', 'availability', 'settings', 'uninstall', 'notes' 1748 ); 1749 1750 foreach ($plugininfo as $type => $plugins) { 1751 $heading = $pluginman->plugintype_name_plural($type); 1752 $pluginclass = core_plugin_manager::resolve_plugininfo_class($type); 1753 if ($manageurl = $pluginclass::get_manage_url()) { 1754 $heading .= $this->output->action_icon($manageurl, new pix_icon('i/settings', 1755 get_string('settings', 'core_plugin'))); 1756 } 1757 $header = new html_table_cell(html_writer::tag('span', $heading, array('id'=>'plugin_type_cell_'.$type))); 1758 $header->header = true; 1759 $header->colspan = array_sum($table->headspan); 1760 $header = new html_table_row(array($header)); 1761 $header->attributes['class'] = 'plugintypeheader type-' . $type; 1762 $table->data[] = $header; 1763 1764 if (empty($plugins)) { 1765 $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin')); 1766 $msg->colspan = array_sum($table->headspan); 1767 $row = new html_table_row(array($msg)); 1768 $row->attributes['class'] .= 'msg msg-noneinstalled'; 1769 $table->data[] = $row; 1770 continue; 1771 } 1772 1773 foreach ($plugins as $name => $plugin) { 1774 $row = new html_table_row(); 1775 $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name; 1776 1777 if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name, null)) { 1778 $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'icon pluginicon')); 1779 } else { 1780 $icon = $this->output->spacer(); 1781 } 1782 $status = $plugin->get_status(); 1783 $row->attributes['class'] .= ' status-'.$status; 1784 $pluginname = html_writer::tag('div', $icon.$plugin->displayname, array('class' => 'displayname')). 1785 html_writer::tag('div', $plugin->component, array('class' => 'componentname')); 1786 $pluginname = new html_table_cell($pluginname); 1787 1788 $version = html_writer::div($plugin->versiondb, 'versionnumber'); 1789 if ((string)$plugin->release !== '') { 1790 $version = html_writer::div($plugin->release, 'release').$version; 1791 } 1792 $version = new html_table_cell($version); 1793 1794 $isenabled = $plugin->is_enabled(); 1795 if (is_null($isenabled)) { 1796 $availability = new html_table_cell(''); 1797 } else if ($isenabled) { 1798 $row->attributes['class'] .= ' enabled'; 1799 $availability = new html_table_cell(get_string('pluginenabled', 'core_plugin')); 1800 } else { 1801 $row->attributes['class'] .= ' disabled'; 1802 $availability = new html_table_cell(get_string('plugindisabled', 'core_plugin')); 1803 } 1804 1805 $settingsurl = $plugin->get_settings_url(); 1806 if (!is_null($settingsurl)) { 1807 $settings = html_writer::link($settingsurl, get_string('settings', 'core_plugin'), array('class' => 'settings')); 1808 } else { 1809 $settings = ''; 1810 } 1811 $settings = new html_table_cell($settings); 1812 1813 if ($uninstallurl = $pluginman->get_uninstall_url($plugin->component, 'overview')) { 1814 $uninstall = html_writer::link($uninstallurl, get_string('uninstall', 'core_plugin')); 1815 } else { 1816 $uninstall = ''; 1817 } 1818 $uninstall = new html_table_cell($uninstall); 1819 1820 if ($plugin->is_standard()) { 1821 $row->attributes['class'] .= ' standard'; 1822 $source = ''; 1823 } else { 1824 $row->attributes['class'] .= ' extension'; 1825 $source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge badge-info'); 1826 } 1827 1828 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) { 1829 $msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge badge-danger'); 1830 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) { 1831 $msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge badge-success'); 1832 } else { 1833 $msg = ''; 1834 } 1835 1836 $requriedby = $pluginman->other_plugins_that_require($plugin->component); 1837 if ($requriedby) { 1838 $requiredby = html_writer::tag('div', get_string('requiredby', 'core_plugin', implode(', ', $requriedby)), 1839 array('class' => 'requiredby')); 1840 } else { 1841 $requiredby = ''; 1842 } 1843 1844 $updateinfo = ''; 1845 if (is_array($plugin->available_updates())) { 1846 foreach ($plugin->available_updates() as $availableupdate) { 1847 $updateinfo .= $this->plugin_available_update_info($pluginman, $availableupdate); 1848 } 1849 } 1850 1851 $notes = new html_table_cell($source.$msg.$requiredby.$updateinfo); 1852 1853 $row->cells = array( 1854 $pluginname, $version, $availability, $settings, $uninstall, $notes 1855 ); 1856 $table->data[] = $row; 1857 } 1858 } 1859 1860 return html_writer::table($table); 1861 } 1862 1863 /** 1864 * Helper method to render the information about the available plugin update 1865 * 1866 * @param core_plugin_manager $pluginman plugin manager instance 1867 * @param \core\update\info $updateinfo information about the available update for the plugin 1868 */ 1869 protected function plugin_available_update_info(core_plugin_manager $pluginman, \core\update\info $updateinfo) { 1870 1871 $boxclasses = 'pluginupdateinfo'; 1872 $info = array(); 1873 1874 if (isset($updateinfo->release)) { 1875 $info[] = html_writer::div( 1876 get_string('updateavailable_release', 'core_plugin', $updateinfo->release), 1877 'info release' 1878 ); 1879 } 1880 1881 if (isset($updateinfo->maturity)) { 1882 $info[] = html_writer::div( 1883 get_string('maturity'.$updateinfo->maturity, 'core_admin'), 1884 'info maturity' 1885 ); 1886 $boxclasses .= ' maturity'.$updateinfo->maturity; 1887 } 1888 1889 if (isset($updateinfo->download)) { 1890 $info[] = html_writer::div( 1891 html_writer::link($updateinfo->download, get_string('download')), 1892 'info download' 1893 ); 1894 } 1895 1896 if (isset($updateinfo->url)) { 1897 $info[] = html_writer::div( 1898 html_writer::link($updateinfo->url, get_string('updateavailable_moreinfo', 'core_plugin')), 1899 'info more' 1900 ); 1901 } 1902 1903 $box = html_writer::start_div($boxclasses); 1904 $box .= html_writer::div( 1905 get_string('updateavailable', 'core_plugin', $updateinfo->version), 1906 'version' 1907 ); 1908 $box .= html_writer::div( 1909 implode(html_writer::span(' ', 'separator'), $info), 1910 'infos' 1911 ); 1912 1913 if ($pluginman->is_remote_plugin_installable($updateinfo->component, $updateinfo->version, $reason, false)) { 1914 $box .= $this->output->single_button( 1915 new moodle_url($this->page->url, array('installupdate' => $updateinfo->component, 1916 'installupdateversion' => $updateinfo->version)), 1917 get_string('updateavailableinstall', 'core_admin'), 1918 'post', 1919 array('class' => 'singlebutton updateavailableinstall') 1920 ); 1921 } else { 1922 $reasonhelp = $this->info_remote_plugin_not_installable($reason); 1923 if ($reasonhelp) { 1924 $box .= html_writer::div($reasonhelp, 'reasonhelp updateavailableinstall'); 1925 } 1926 } 1927 $box .= html_writer::end_div(); 1928 1929 return $box; 1930 } 1931 1932 /** 1933 * This function will render one beautiful table with all the environmental 1934 * configuration and how it suits Moodle needs. 1935 * 1936 * @param boolean $result final result of the check (true/false) 1937 * @param environment_results[] $environment_results array of results gathered 1938 * @return string HTML to output. 1939 */ 1940 public function environment_check_table($result, $environment_results) { 1941 global $CFG; 1942 1943 // Table headers 1944 $servertable = new html_table();//table for server checks 1945 $servertable->head = array( 1946 get_string('name'), 1947 get_string('info'), 1948 get_string('report'), 1949 get_string('plugin'), 1950 get_string('status'), 1951 ); 1952 $servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'leftalign plugin', 'centeralign status'); 1953 $servertable->attributes['class'] = 'admintable environmenttable generaltable table-sm'; 1954 $servertable->id = 'serverstatus'; 1955 1956 $serverdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array()); 1957 1958 $othertable = new html_table();//table for custom checks 1959 $othertable->head = array( 1960 get_string('info'), 1961 get_string('report'), 1962 get_string('plugin'), 1963 get_string('status'), 1964 ); 1965 $othertable->colclasses = array('aligncenter info', 'alignleft report', 'alignleft plugin', 'aligncenter status'); 1966 $othertable->attributes['class'] = 'admintable environmenttable generaltable table-sm'; 1967 $othertable->id = 'otherserverstatus'; 1968 1969 $otherdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array()); 1970 1971 // Iterate over each environment_result 1972 $continue = true; 1973 foreach ($environment_results as $environment_result) { 1974 $errorline = false; 1975 $warningline = false; 1976 $stringtouse = ''; 1977 if ($continue) { 1978 $type = $environment_result->getPart(); 1979 $info = $environment_result->getInfo(); 1980 $status = $environment_result->getStatus(); 1981 $plugin = $environment_result->getPluginName(); 1982 $error_code = $environment_result->getErrorCode(); 1983 // Process Report field 1984 $rec = new stdClass(); 1985 // Something has gone wrong at parsing time 1986 if ($error_code) { 1987 $stringtouse = 'environmentxmlerror'; 1988 $rec->error_code = $error_code; 1989 $status = get_string('error'); 1990 $errorline = true; 1991 $continue = false; 1992 } 1993 1994 if ($continue) { 1995 if ($rec->needed = $environment_result->getNeededVersion()) { 1996 // We are comparing versions 1997 $rec->current = $environment_result->getCurrentVersion(); 1998 if ($environment_result->getLevel() == 'required') { 1999 $stringtouse = 'environmentrequireversion'; 2000 } else { 2001 $stringtouse = 'environmentrecommendversion'; 2002 } 2003 2004 } else if ($environment_result->getPart() == 'custom_check') { 2005 // We are checking installed & enabled things 2006 if ($environment_result->getLevel() == 'required') { 2007 $stringtouse = 'environmentrequirecustomcheck'; 2008 } else { 2009 $stringtouse = 'environmentrecommendcustomcheck'; 2010 } 2011 2012 } else if ($environment_result->getPart() == 'php_setting') { 2013 if ($status) { 2014 $stringtouse = 'environmentsettingok'; 2015 } else if ($environment_result->getLevel() == 'required') { 2016 $stringtouse = 'environmentmustfixsetting'; 2017 } else { 2018 $stringtouse = 'environmentshouldfixsetting'; 2019 } 2020 2021 } else { 2022 if ($environment_result->getLevel() == 'required') { 2023 $stringtouse = 'environmentrequireinstall'; 2024 } else { 2025 $stringtouse = 'environmentrecommendinstall'; 2026 } 2027 } 2028 2029 // Calculate the status value 2030 if ($environment_result->getBypassStr() != '') { //Handle bypassed result (warning) 2031 $status = get_string('bypassed'); 2032 $warningline = true; 2033 } else if ($environment_result->getRestrictStr() != '') { //Handle restricted result (error) 2034 $status = get_string('restricted'); 2035 $errorline = true; 2036 } else { 2037 if ($status) { //Handle ok result (ok) 2038 $status = get_string('ok'); 2039 } else { 2040 if ($environment_result->getLevel() == 'optional') {//Handle check result (warning) 2041 $status = get_string('check'); 2042 $warningline = true; 2043 } else { //Handle error result (error) 2044 $status = get_string('check'); 2045 $errorline = true; 2046 } 2047 } 2048 } 2049 } 2050 2051 // Build the text 2052 $linkparts = array(); 2053 $linkparts[] = 'admin/environment'; 2054 $linkparts[] = $type; 2055 if (!empty($info)){ 2056 $linkparts[] = $info; 2057 } 2058 // Plugin environments do not have docs pages yet. 2059 if (empty($CFG->docroot) or $environment_result->plugin) { 2060 $report = get_string($stringtouse, 'admin', $rec); 2061 } else { 2062 $report = $this->doc_link(join('/', $linkparts), get_string($stringtouse, 'admin', $rec), true); 2063 } 2064 // Enclose report text in div so feedback text will be displayed underneath it. 2065 $report = html_writer::div($report); 2066 2067 // Format error or warning line 2068 if ($errorline) { 2069 $messagetype = 'error'; 2070 $statusclass = 'badge-danger'; 2071 } else if ($warningline) { 2072 $messagetype = 'warn'; 2073 $statusclass = 'badge-warning'; 2074 } else { 2075 $messagetype = 'ok'; 2076 $statusclass = 'badge-success'; 2077 } 2078 $status = html_writer::span($status, 'badge ' . $statusclass); 2079 // Here we'll store all the feedback found 2080 $feedbacktext = ''; 2081 // Append the feedback if there is some 2082 $feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(), $messagetype); 2083 //Append the bypass if there is some 2084 $feedbacktext .= $environment_result->strToReport($environment_result->getBypassStr(), 'warn'); 2085 //Append the restrict if there is some 2086 $feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(), 'error'); 2087 2088 $report .= $feedbacktext; 2089 2090 // Add the row to the table 2091 if ($environment_result->getPart() == 'custom_check'){ 2092 $otherdata[$messagetype][] = array ($info, $report, $plugin, $status); 2093 } else { 2094 $serverdata[$messagetype][] = array ($type, $info, $report, $plugin, $status); 2095 } 2096 } 2097 } 2098 2099 //put errors first in 2100 $servertable->data = array_merge($serverdata['error'], $serverdata['warn'], $serverdata['ok']); 2101 $othertable->data = array_merge($otherdata['error'], $otherdata['warn'], $otherdata['ok']); 2102 2103 // Print table 2104 $output = ''; 2105 $output .= $this->heading(get_string('serverchecks', 'admin')); 2106 $output .= html_writer::table($servertable); 2107 if (count($othertable->data)){ 2108 $output .= $this->heading(get_string('customcheck', 'admin')); 2109 $output .= html_writer::table($othertable); 2110 } 2111 2112 // Finally, if any error has happened, print the summary box 2113 if (!$result) { 2114 $output .= $this->box(get_string('environmenterrortodo', 'admin'), 'environmentbox errorbox'); 2115 } 2116 2117 return $output; 2118 } 2119 2120 /** 2121 * Render a simple page for providing the upgrade key. 2122 * 2123 * @param moodle_url|string $url 2124 * @return string 2125 */ 2126 public function upgradekey_form_page($url) { 2127 2128 $output = ''; 2129 $output .= $this->header(); 2130 $output .= $this->container_start('upgradekeyreq'); 2131 $output .= $this->heading(get_string('upgradekeyreq', 'core_admin')); 2132 $output .= html_writer::start_tag('form', array('method' => 'POST', 'action' => $url)); 2133 $output .= html_writer::empty_tag('input', array('name' => 'upgradekey', 'type' => 'password')); 2134 $output .= html_writer::empty_tag('input', array('value' => get_string('submit'), 'type' => 'submit')); 2135 $output .= html_writer::end_tag('form'); 2136 $output .= $this->container_end(); 2137 $output .= $this->footer(); 2138 2139 return $output; 2140 } 2141 2142 /** 2143 * Check to see if writing to the deprecated legacy log store is enabled. 2144 * 2145 * @return string An error message if writing to the legacy log store is enabled. 2146 */ 2147 protected function legacy_log_store_writing_error() { 2148 $enabled = get_config('logstore_legacy', 'loglegacy'); 2149 $plugins = explode(',', get_config('tool_log', 'enabled_stores')); 2150 $enabled = $enabled && in_array('logstore_legacy', $plugins); 2151 2152 if ($enabled) { 2153 return $this->warning(get_string('legacylogginginuse')); 2154 } 2155 } 2156 2157 /** 2158 * Display message about the benefits of registering on Moodle.org 2159 * 2160 * @return string 2161 */ 2162 public function moodleorg_registration_message() { 2163 2164 $out = format_text(get_string('registerwithmoodleorginfo', 'core_hub'), FORMAT_MARKDOWN); 2165 2166 $out .= html_writer::link( 2167 new moodle_url('/admin/settings.php', ['section' => 'moodleservices']), 2168 $this->output->pix_icon('i/info', '').' '.get_string('registerwithmoodleorginfoapp', 'core_hub'), 2169 ['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href'] 2170 ); 2171 2172 $out .= html_writer::link( 2173 HUB_MOODLEORGHUBURL, 2174 $this->output->pix_icon('i/stats', '').' '.get_string('registerwithmoodleorginfostats', 'core_hub'), 2175 ['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href'] 2176 ); 2177 2178 $out .= html_writer::link( 2179 HUB_MOODLEORGHUBURL.'/sites', 2180 $this->output->pix_icon('i/location', '').' '.get_string('registerwithmoodleorginfosites', 'core_hub'), 2181 ['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href'] 2182 ); 2183 2184 return $this->output->box($out); 2185 } 2186 2187 /** 2188 * Display message about benefits of enabling the user feedback feature. 2189 * 2190 * @param bool $showfeedbackencouragement Whether the encouragement content should be displayed or not 2191 * @return string 2192 */ 2193 protected function userfeedback_encouragement(bool $showfeedbackencouragement): string { 2194 $output = ''; 2195 2196 if ($showfeedbackencouragement) { 2197 $settingslink = new moodle_url('/admin/settings.php', ['section' => 'userfeedback']); 2198 $output .= $this->warning(get_string('userfeedbackencouragement', 'admin', $settingslink->out()), 'info'); 2199 } 2200 2201 return $output; 2202 } 2203 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body