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