MDL-49329 admin: Improve the styling of the Plugins check screen
[moodle.git] / admin / renderer.php
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/>.
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  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Standard HTML output renderer for core_admin subsystem
31  */
32 class core_admin_renderer extends plugin_renderer_base {
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 = '';
43         $copyrightnotice = text_to_html(get_string('gpl3'));
44         $copyrightnotice = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $copyrightnotice); // extremely ugly validation hack
46         $continue = new single_button(new moodle_url($this->page->url, array(
47             'lang' => $CFG->lang, 'agreelicense' => 1)), get_string('continue'), 'get');
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();
57         return $output;
58     }
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();
77         return $output;
78     }
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 = '';
92         $output .= $this->header();
93         $output .= $this->maturity_warning($maturity);
94         $output .= $this->heading("Moodle $release");
95         $output .= $this->release_notes_link();
97         $output .= $this->environment_check_table($envstatus, $environment_results);
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         }
107         $output .= $this->footer();
108         return $output;
109     }
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 = '';
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);
129         $output .= $this->footer();
131         return $output;
132     }
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 = '';
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');
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();
155         return $output;
156     }
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 = '';
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);
174         if (!$envstatus) {
175             $output .= $this->upgrade_reload(new moodle_url($this->page->url, array('confirmupgrade' => 1, 'cache' => 0)));
177         } else {
178             $output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess');
180             if (empty($CFG->skiplangupgrade) and current_language() !== 'en') {
181                 $output .= $this->box(get_string('langpackwillbeupdated', 'admin'), 'generalbox', 'notice');
182             }
184             $output .= $this->continue_button(new moodle_url($this->page->url, array(
185                 'confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0)));
186         }
188         $output .= $this->footer();
190         return $output;
191     }
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         global $CFG;
207         $output = '';
209         $output .= $this->header();
210         $output .= $this->box_start('generalbox');
211         $output .= $this->container_start('generalbox', 'notice');
212         $output .= html_writer::tag('p', get_string('pluginchecknotice', 'core_plugin'));
213         if (empty($CFG->disableupdatenotifications)) {
214             $output .= $this->container_start('checkforupdates');
215             $output .= $this->single_button(new moodle_url($reloadurl, array('fetchupdates' => 1)), get_string('checkforupdates', 'core_plugin'));
216             if ($timefetched = $checker->get_last_timefetched()) {
217                 $output .= $this->container(get_string('checkforupdateslast', 'core_plugin',
218                     userdate($timefetched, get_string('strftimedatetime', 'core_langconfig'))));
219             }
220             $output .= $this->container_end();
221         }
222         $output .= $this->container_end();
224         $output .= $this->plugins_check_table($pluginman, $version, array('full' => $showallplugins));
225         $output .= $this->box_end();
226         $output .= $this->upgrade_reload($reloadurl);
228         if ($pluginman->some_plugins_updatable()) {
229             $output .= $this->container_start('upgradepluginsinfo');
230             $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin'));
231             $output .= $this->container_end();
232         }
234         $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get');
235         $button->class = 'continuebutton';
236         $output .= $this->render($button);
237         $output .= $this->footer();
239         return $output;
240     }
242     /**
243      * Prints a page with a summary of plugin deployment to be confirmed.
244      *
245      * @param \core\update\deployer $deployer
246      * @param array $data deployer's data package as returned by {@link \core\update\deployer::submitted_data()}
247      * @return string
248      */
249     public function upgrade_plugin_confirm_deploy_page(\core\update\deployer $deployer, array $data) {
251         if (!$deployer->initialized()) {
252             throw new coding_exception('Unable to render a page for non-initialized deployer.');
253         }
255         if (empty($data['updateinfo'])) {
256             throw new coding_exception('Missing required data component.');
257         }
259         $updateinfo = $data['updateinfo'];
261         $output  = '';
262         $output .= $this->header();
263         $output .= $this->container_start('generalbox updateplugin', 'notice');
265         $a = new stdClass();
266         if (get_string_manager()->string_exists('pluginname', $updateinfo->component)) {
267             $a->name = get_string('pluginname', $updateinfo->component);
268         } else {
269             $a->name = $updateinfo->component;
270         }
272         if (isset($updateinfo->release)) {
273             $a->version = $updateinfo->release . ' (' . $updateinfo->version . ')';
274         } else {
275             $a->version = $updateinfo->version;
276         }
277         $a->url = $updateinfo->download;
279         $output .= $this->output->heading(get_string('updatepluginconfirm', 'core_plugin'));
280         $output .= $this->output->container(format_text(get_string('updatepluginconfirminfo', 'core_plugin', $a)), 'updatepluginconfirminfo');
281         $output .= $this->output->container(get_string('updatepluginconfirmwarning', 'core_plugin', 'updatepluginconfirmwarning'));
283         if ($repotype = $deployer->plugin_external_source($data['updateinfo'])) {
284             $output .= $this->output->container(get_string('updatepluginconfirmexternal', 'core_plugin', $repotype), 'updatepluginconfirmexternal');
285         }
287         $widget = $deployer->make_execution_widget($data['updateinfo'], $data['returnurl']);
288         $output .= $this->output->render($widget);
290         $output .= $this->output->single_button($data['callerurl'], get_string('cancel', 'core'), 'get');
292         $output .= $this->container_end();
293         $output .= $this->footer();
295         return $output;
296     }
298     /**
299      * Display the admin notifications page.
300      * @param int $maturity
301      * @param bool $insecuredataroot warn dataroot is invalid
302      * @param bool $errorsdisplayed warn invalid dispaly error setting
303      * @param bool $cronoverdue warn cron not running
304      * @param bool $dbproblems warn db has problems
305      * @param bool $maintenancemode warn in maintenance mode
306      * @param bool $buggyiconvnomb warn iconv problems
307      * @param array|null $availableupdates array of \core\update\info objects or null
308      * @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
309      * @param string[] $cachewarnings An array containing warnings from the Cache API.
310      *
311      * @return string HTML to output.
312      */
313     public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
314             $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
315             $buggyiconvnomb, $registered, array $cachewarnings = array()) {
316         global $CFG;
317         $output = '';
319         $output .= $this->header();
320         $output .= $this->maturity_info($maturity);
321         $output .= empty($CFG->disableupdatenotifications) ? $this->available_updates($availableupdates, $availableupdatesfetch) : '';
322         $output .= $this->insecure_dataroot_warning($insecuredataroot);
323         $output .= $this->display_errors_warning($errorsdisplayed);
324         $output .= $this->buggy_iconv_warning($buggyiconvnomb);
325         $output .= $this->cron_overdue_warning($cronoverdue);
326         $output .= $this->db_problems($dbproblems);
327         $output .= $this->maintenance_mode_warning($maintenancemode);
328         $output .= $this->cache_warnings($cachewarnings);
329         $output .= $this->registration_warning($registered);
331         //////////////////////////////////////////////////////////////////////////////////////////////////
332         ////  IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
333         $output .= $this->moodle_copyright();
334         //////////////////////////////////////////////////////////////////////////////////////////////////
336         $output .= $this->footer();
338         return $output;
339     }
341     /**
342      * Display the plugin management page (admin/plugins.php).
343      *
344      * The filtering options array may contain following items:
345      *  bool contribonly - show only contributed extensions
346      *  bool updatesonly - show only plugins with an available update
347      *
348      * @param core_plugin_manager $pluginman
349      * @param \core\update\checker $checker
350      * @param array $options filtering options
351      * @return string HTML to output.
352      */
353     public function plugin_management_page(core_plugin_manager $pluginman, \core\update\checker $checker, array $options = array()) {
354         global $CFG;
356         $output = '';
358         $output .= $this->header();
359         $output .= $this->heading(get_string('pluginsoverview', 'core_admin'));
360         $output .= $this->plugins_overview_panel($pluginman, $options);
362         if (empty($CFG->disableupdatenotifications)) {
363             $output .= $this->container_start('checkforupdates');
364             $output .= $this->single_button(
365                 new moodle_url($this->page->url, array_merge($options, array('fetchremote' => 1))),
366                 get_string('checkforupdates', 'core_plugin')
367             );
368             if ($timefetched = $checker->get_last_timefetched()) {
369                 $output .= $this->container(get_string('checkforupdateslast', 'core_plugin',
370                     userdate($timefetched, get_string('strftimedatetime', 'core_langconfig'))));
371             }
372             $output .= $this->container_end();
373         }
375         $output .= $this->box($this->plugins_control_panel($pluginman, $options), 'generalbox');
376         $output .= $this->footer();
378         return $output;
379     }
381     /**
382      * Display a page to confirm the plugin uninstallation.
383      *
384      * @param core_plugin_manager $pluginman
385      * @param \core\plugininfo\base $pluginfo
386      * @param moodle_url $continueurl URL to continue after confirmation
387      * @param moodle_url $cancelurl URL to to go if cancelled
388      * @return string
389      */
390     public function plugin_uninstall_confirm_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo, moodle_url $continueurl, moodle_url $cancelurl) {
391         $output = '';
393         $pluginname = $pluginman->plugin_name($pluginfo->component);
395         $confirm = '<p>' . get_string('uninstallconfirm', 'core_plugin', array('name' => $pluginname)) . '</p>';
396         if ($extraconfirm = $pluginfo->get_uninstall_extra_warning()) {
397             $confirm .= $extraconfirm;
398         }
400         $output .= $this->output->header();
401         $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
402         $output .= $this->output->confirm($confirm, $continueurl, $cancelurl);
403         $output .= $this->output->footer();
405         return $output;
406     }
408     /**
409      * Display a page with results of plugin uninstallation and offer removal of plugin files.
410      *
411      * @param core_plugin_manager $pluginman
412      * @param \core\plugininfo\base $pluginfo
413      * @param progress_trace_buffer $progress
414      * @param moodle_url $continueurl URL to continue to remove the plugin folder
415      * @return string
416      */
417     public function plugin_uninstall_results_removable_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo,
418                                                             progress_trace_buffer $progress, moodle_url $continueurl) {
419         $output = '';
421         $pluginname = $pluginman->plugin_name($pluginfo->component);
423         // Do not show navigation here, they must click one of the buttons.
424         $this->page->set_pagelayout('maintenance');
425         $this->page->set_cacheable(false);
427         $output .= $this->output->header();
428         $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
430         $output .= $this->output->box($progress->get_buffer(), 'generalbox uninstallresultmessage');
432         $confirm = $this->output->container(get_string('uninstalldeleteconfirm', 'core_plugin',
433             array('name' => $pluginname, 'rootdir' => $pluginfo->rootdir)), 'uninstalldeleteconfirm');
435         if ($repotype = $pluginman->plugin_external_source($pluginfo->component)) {
436             $confirm .= $this->output->container(get_string('uninstalldeleteconfirmexternal', 'core_plugin', $repotype),
437                 'uninstalldeleteconfirmexternal');
438         }
440         // After any uninstall we must execute full upgrade to finish the cleanup!
441         $output .= $this->output->confirm($confirm, $continueurl, new moodle_url('/admin/index.php'));
442         $output .= $this->output->footer();
444         return $output;
445     }
447     /**
448      * Display a page with results of plugin uninstallation and inform about the need to remove plugin files manually.
449      *
450      * @param core_plugin_manager $pluginman
451      * @param \core\plugininfo\base $pluginfo
452      * @param progress_trace_buffer $progress
453      * @return string
454      */
455     public function plugin_uninstall_results_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo, progress_trace_buffer $progress) {
456         $output = '';
458         $pluginname = $pluginfo->component;
460         $output .= $this->output->header();
461         $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
463         $output .= $this->output->box($progress->get_buffer(), 'generalbox uninstallresultmessage');
465         $output .= $this->output->box(get_string('uninstalldelete', 'core_plugin',
466             array('name' => $pluginname, 'rootdir' => $pluginfo->rootdir)), 'generalbox uninstalldelete');
467         $output .= $this->output->continue_button(new moodle_url('/admin/index.php'));
468         $output .= $this->output->footer();
470         return $output;
471     }
473     /**
474      * Display the plugin management page (admin/environment.php).
475      * @param array $versions
476      * @param string $version
477      * @param boolean $envstatus final result of env check (true/false)
478      * @param array $environment_results array of results gathered
479      * @return string HTML to output.
480      */
481     public function environment_check_page($versions, $version, $envstatus, $environment_results) {
482         $output = '';
483         $output .= $this->header();
485         // Print the component download link
486         $output .= html_writer::tag('div', html_writer::link(
487                     new moodle_url('/admin/environment.php', array('action' => 'updatecomponent', 'sesskey' => sesskey())),
488                     get_string('updatecomponent', 'admin')),
489                 array('class' => 'reportlink'));
491         // Heading.
492         $output .= $this->heading(get_string('environment', 'admin'));
494         // Box with info and a menu to choose the version.
495         $output .= $this->box_start();
496         $output .= html_writer::tag('div', get_string('adminhelpenvironment'));
497         $select = new single_select(new moodle_url('/admin/environment.php'), 'version', $versions, $version, null);
498         $select->label = get_string('moodleversion');
499         $output .= $this->render($select);
500         $output .= $this->box_end();
502         // The results
503         $output .= $this->environment_check_table($envstatus, $environment_results);
505         $output .= $this->footer();
506         return $output;
507     }
509     /**
510      * Output a warning message, of the type that appears on the admin notifications page.
511      * @param string $message the message to display.
512      * @param string $type type class
513      * @return string HTML to output.
514      */
515     protected function warning($message, $type = 'warning') {
516         return $this->box($message, 'generalbox admin' . $type);
517     }
519     /**
520      * Render an appropriate message if dataroot is insecure.
521      * @param bool $insecuredataroot
522      * @return string HTML to output.
523      */
524     protected function insecure_dataroot_warning($insecuredataroot) {
525         global $CFG;
527         if ($insecuredataroot == INSECURE_DATAROOT_WARNING) {
528             return $this->warning(get_string('datarootsecuritywarning', 'admin', $CFG->dataroot));
530         } else if ($insecuredataroot == INSECURE_DATAROOT_ERROR) {
531             return $this->warning(get_string('datarootsecurityerror', 'admin', $CFG->dataroot), 'error');
533         } else {
534             return '';
535         }
536     }
538     /**
539      * Render an appropriate message if dataroot is insecure.
540      * @param bool $errorsdisplayed
541      * @return string HTML to output.
542      */
543     protected function display_errors_warning($errorsdisplayed) {
544         if (!$errorsdisplayed) {
545             return '';
546         }
548         return $this->warning(get_string('displayerrorswarning', 'admin'));
549     }
551     /**
552      * Render an appropriate message if iconv is buggy and mbstring missing.
553      * @param bool $buggyiconvnomb
554      * @return string HTML to output.
555      */
556     protected function buggy_iconv_warning($buggyiconvnomb) {
557         if (!$buggyiconvnomb) {
558             return '';
559         }
561         return $this->warning(get_string('warningiconvbuggy', 'admin'));
562     }
564     /**
565      * Render an appropriate message if cron has not been run recently.
566      * @param bool $cronoverdue
567      * @return string HTML to output.
568      */
569     public function cron_overdue_warning($cronoverdue) {
570         global $CFG;
571         if (!$cronoverdue) {
572             return '';
573         }
575         if (empty($CFG->cronclionly)) {
576             $url = new moodle_url('/admin/cron.php');
577             if (!empty($CFG->cronremotepassword)) {
578                 $url = new moodle_url('/admin/cron.php', array('password' => $CFG->cronremotepassword));
579             }
581             return $this->warning(get_string('cronwarning', 'admin', $url->out()) . '&nbsp;' .
582                     $this->help_icon('cron', 'admin'));
583         }
585         // $CFG->cronclionly is not empty: cron can run only from CLI.
586         return $this->warning(get_string('cronwarningcli', 'admin') . '&nbsp;' .
587                 $this->help_icon('cron', 'admin'));
588     }
590     /**
591      * Render an appropriate message if there are any problems with the DB set-up.
592      * @param bool $dbproblems
593      * @return string HTML to output.
594      */
595     public function db_problems($dbproblems) {
596         if (!$dbproblems) {
597             return '';
598         }
600         return $this->warning($dbproblems);
601     }
603     /**
604      * Renders cache warnings if there are any.
605      *
606      * @param string[] $cachewarnings
607      * @return string
608      */
609     public function cache_warnings(array $cachewarnings) {
610         if (!count($cachewarnings)) {
611             return '';
612         }
613         return join("\n", array_map(array($this, 'warning'), $cachewarnings));
614     }
616     /**
617      * Render an appropriate message if the site in in maintenance mode.
618      * @param bool $maintenancemode
619      * @return string HTML to output.
620      */
621     public function maintenance_mode_warning($maintenancemode) {
622         if (!$maintenancemode) {
623             return '';
624         }
626         $url = new moodle_url('/admin/settings.php', array('section' => 'maintenancemode'));
627         $url = $url->out(); // get_string() does not support objects in params
629         return $this->warning(get_string('sitemaintenancewarning2', 'admin', $url));
630     }
632     /**
633      * Display a warning about installing development code if necesary.
634      * @param int $maturity
635      * @return string HTML to output.
636      */
637     protected function maturity_warning($maturity) {
638         if ($maturity == MATURITY_STABLE) {
639             return ''; // No worries.
640         }
642         $maturitylevel = get_string('maturity' . $maturity, 'admin');
643         return $this->warning(
644                     $this->container(get_string('maturitycorewarning', 'admin', $maturitylevel)) .
645                     $this->container($this->doc_link('admin/versions', get_string('morehelp'))),
646                 'error');
647     }
649     /*
650      * If necessary, displays a warning about upgrading a test site.
651      *
652      * @param string $testsite
653      * @return string HTML
654      */
655     protected function test_site_warning($testsite) {
657         if (!$testsite) {
658             return '';
659         }
661         $warning = (get_string('testsiteupgradewarning', 'admin', $testsite));
662         return $this->warning($warning, 'error');
663     }
665     /**
666      * Output the copyright notice.
667      * @return string HTML to output.
668      */
669     protected function moodle_copyright() {
670         global $CFG;
672         //////////////////////////////////////////////////////////////////////////////////////////////////
673         ////  IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
674         $copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
675                          '<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
676                          'Copyright &copy; 1999 onwards, Martin Dougiamas<br />'.
677                          'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'.
678                          '<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
679         //////////////////////////////////////////////////////////////////////////////////////////////////
681         return $this->box($copyrighttext, 'copyright');
682     }
684     /**
685      * Display a warning about installing development code if necesary.
686      * @param int $maturity
687      * @return string HTML to output.
688      */
689     protected function maturity_info($maturity) {
690         if ($maturity == MATURITY_STABLE) {
691             return ''; // No worries.
692         }
694         $level = 'warning';
696         if ($maturity == MATURITY_ALPHA) {
697             $level = 'error';
698         }
700         $maturitylevel = get_string('maturity' . $maturity, 'admin');
701         $warningtext = get_string('maturitycoreinfo', 'admin', $maturitylevel);
702         $warningtext .= ' ' . $this->doc_link('admin/versions', get_string('morehelp'));
703         return $this->warning($warningtext, $level);
704     }
706     /**
707      * Displays the info about available Moodle core and plugin updates
708      *
709      * The structure of the $updates param has changed since 2.4. It contains not only updates
710      * for the core itself, but also for all other installed plugins.
711      *
712      * @param array|null $updates array of (string)component => array of \core\update\info objects or null
713      * @param int|null $fetch timestamp of the most recent updates fetch or null (unknown)
714      * @return string
715      */
716     protected function available_updates($updates, $fetch) {
718         $updateinfo = '';
719         $someupdateavailable = false;
720         if (is_array($updates)) {
721             if (is_array($updates['core'])) {
722                 $someupdateavailable = true;
723                 $updateinfo .= $this->heading(get_string('updateavailable', 'core_admin'), 3);
724                 foreach ($updates['core'] as $update) {
725                     $updateinfo .= $this->moodle_available_update_info($update);
726                 }
727                 $updateinfo .= html_writer::tag('p', get_string('updateavailablerecommendation', 'core_admin'),
728                     array('class' => 'updateavailablerecommendation'));
729             }
730             unset($updates['core']);
731             // If something has left in the $updates array now, it is updates for plugins.
732             if (!empty($updates)) {
733                 $someupdateavailable = true;
734                 $updateinfo .= $this->heading(get_string('updateavailableforplugin', 'core_admin'), 3);
735                 $pluginsoverviewurl = new moodle_url('/admin/plugins.php', array('updatesonly' => 1));
736                 $updateinfo .= $this->container(get_string('pluginsoverviewsee', 'core_admin',
737                     array('url' => $pluginsoverviewurl->out())));
738             }
739         }
741         if (!$someupdateavailable) {
742             $now = time();
743             if ($fetch and ($fetch <= $now) and ($now - $fetch < HOURSECS)) {
744                 $updateinfo .= $this->heading(get_string('updateavailablenot', 'core_admin'), 3);
745             }
746         }
748         $updateinfo .= $this->container_start('checkforupdates');
749         $fetchurl = new moodle_url('/admin/index.php', array('fetchupdates' => 1, 'sesskey' => sesskey(), 'cache' => 0));
750         $updateinfo .= $this->single_button($fetchurl, get_string('checkforupdates', 'core_plugin'));
751         if ($fetch) {
752             $updateinfo .= $this->container(get_string('checkforupdateslast', 'core_plugin',
753                 userdate($fetch, get_string('strftimedatetime', 'core_langconfig'))));
754         }
755         $updateinfo .= $this->container_end();
757         return $this->warning($updateinfo);
758     }
760     /**
761      * Display a warning about not being registered on Moodle.org if necesary.
762      *
763      * @param boolean $registered true if the site is registered on Moodle.org
764      * @return string HTML to output.
765      */
766     protected function registration_warning($registered) {
768         if (!$registered) {
770             $registerbutton = $this->single_button(new moodle_url('/admin/registration/register.php',
771                     array('huburl' =>  HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.org')),
772                     get_string('register', 'admin'));
774             return $this->warning( get_string('registrationwarning', 'admin')
775                     . '&nbsp;' . $this->help_icon('registration', 'admin') . $registerbutton );
776         }
778         return '';
779     }
781     /**
782      * Helper method to render the information about the available Moodle update
783      *
784      * @param \core\update\info $updateinfo information about the available Moodle core update
785      */
786     protected function moodle_available_update_info(\core\update\info $updateinfo) {
788         $boxclasses = 'moodleupdateinfo';
789         $info = array();
791         if (isset($updateinfo->release)) {
792             $info[] = html_writer::tag('span', get_string('updateavailable_release', 'core_admin', $updateinfo->release),
793                 array('class' => 'info release'));
794         }
796         if (isset($updateinfo->version)) {
797             $info[] = html_writer::tag('span', get_string('updateavailable_version', 'core_admin', $updateinfo->version),
798                 array('class' => 'info version'));
799         }
801         if (isset($updateinfo->maturity)) {
802             $info[] = html_writer::tag('span', get_string('maturity'.$updateinfo->maturity, 'core_admin'),
803                 array('class' => 'info maturity'));
804             $boxclasses .= ' maturity'.$updateinfo->maturity;
805         }
807         if (isset($updateinfo->download)) {
808             $info[] = html_writer::link($updateinfo->download, get_string('download'), array('class' => 'info download'));
809         }
811         if (isset($updateinfo->url)) {
812             $info[] = html_writer::link($updateinfo->url, get_string('updateavailable_moreinfo', 'core_plugin'),
813                 array('class' => 'info more'));
814         }
816         $box  = $this->output->box_start($boxclasses);
817         $box .= $this->output->box(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $info), '');
818         $box .= $this->output->box_end();
820         return $box;
821     }
823     /**
824      * Display a link to the release notes.
825      * @return string HTML to output.
826      */
827     protected function release_notes_link() {
828         $releasenoteslink = get_string('releasenoteslink', 'admin', 'http://docs.moodle.org/dev/Releases');
829         $releasenoteslink = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $releasenoteslink); // extremely ugly validation hack
830         return $this->box($releasenoteslink, 'generalbox releasenoteslink');
831     }
833     /**
834      * Display the reload link that appears on several upgrade/install pages.
835      * @return string HTML to output.
836      */
837     function upgrade_reload($url) {
838         return html_writer::empty_tag('br') .
839                 html_writer::tag('div',
840                     html_writer::link($url, $this->pix_icon('i/reload', '', '', array('class' => 'icon icon-pre')) .
841                             get_string('reload'), array('title' => get_string('reload'))),
842                 array('class' => 'continuebutton')) . html_writer::empty_tag('br');
843     }
845     /**
846      * Displays all known plugins and information about their installation or upgrade
847      *
848      * This default implementation renders all plugins into one big table. The rendering
849      * options support:
850      *     (bool)full = false: whether to display up-to-date plugins, too
851      *     (bool)xdep = false: display the plugins with unsatisified dependecies only
852      *
853      * @param core_plugin_manager $pluginman provides information about the plugins.
854      * @param int $version the version of the Moodle code from version.php.
855      * @param array $options rendering options
856      * @return string HTML code
857      */
858     public function plugins_check_table(core_plugin_manager $pluginman, $version, array $options = array()) {
859         global $CFG;
861         $plugininfo = $pluginman->get_plugins();
863         if (empty($plugininfo)) {
864             return '';
865         }
867         $options['full'] = isset($options['full']) ? (bool)$options['full'] : false;
868         $options['xdep'] = isset($options['xdep']) ? (bool)$options['xdep'] : false;
870         $table = new html_table();
871         $table->id = 'plugins-check';
872         $table->head = array(
873             get_string('displayname', 'core_plugin').' / '.get_string('rootdir', 'core_plugin'),
874             get_string('versiondb', 'core_plugin'),
875             get_string('versiondisk', 'core_plugin'),
876             get_string('requires', 'core_plugin'),
877             get_string('source', 'core_plugin').' / '.get_string('status', 'core_plugin'),
878         );
879         $table->colclasses = array(
880             'displayname', 'versiondb', 'versiondisk', 'requires', 'status',
881         );
882         $table->data = array();
884         $numofhighlighted = array();    // number of highlighted rows per this subsection
886         foreach ($plugininfo as $type => $plugins) {
888             $header = new html_table_cell($pluginman->plugintype_name_plural($type));
889             $header->header = true;
890             $header->colspan = count($table->head);
891             $header = new html_table_row(array($header));
892             $header->attributes['class'] = 'plugintypeheader type-' . $type;
894             $numofhighlighted[$type] = 0;
896             if (empty($plugins) and $options['full']) {
897                 $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
898                 $msg->colspan = count($table->head);
899                 $row = new html_table_row(array($msg));
900                 $row->attributes['class'] .= 'msg msg-noneinstalled';
901                 $table->data[] = $header;
902                 $table->data[] = $row;
903                 continue;
904             }
906             $plugintyperows = array();
908             foreach ($plugins as $name => $plugin) {
909                 $row = new html_table_row();
910                 $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
912                 if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name, null)) {
913                     $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
914                 } else {
915                     $icon = '';
916                 }
918                 $displayname = new html_table_cell(
919                     $icon.
920                     html_writer::span($plugin->displayname, 'pluginname').
921                     html_writer::div($plugin->get_dir(), 'plugindir')
922                 );
924                 $versiondb = new html_table_cell($plugin->versiondb);
925                 $versiondisk = new html_table_cell($plugin->versiondisk);
927                 if ($isstandard = $plugin->is_standard()) {
928                     $row->attributes['class'] .= ' standard';
929                     $sourcelabel = html_writer::span(get_string('sourcestd', 'core_plugin'), 'sourcetext label');
930                 } else {
931                     $row->attributes['class'] .= ' extension';
932                     $sourcelabel = html_writer::span(get_string('sourceext', 'core_plugin'), 'sourcetext label label-info');
933                 }
935                 $coredependency = $plugin->is_core_dependency_satisfied($version);
936                 $otherpluginsdependencies = $pluginman->are_dependencies_satisfied($plugin->get_other_required_plugins());
937                 $dependenciesok = $coredependency && $otherpluginsdependencies;
939                 $statuscode = $plugin->get_status();
940                 $row->attributes['class'] .= ' status-' . $statuscode;
941                 $statusclass = 'statustext label ';
942                 switch ($statuscode) {
943                     case core_plugin_manager::PLUGIN_STATUS_NEW:
944                         $statusclass .= $dependenciesok ? 'label-success' : 'label-warning';
945                         break;
946                     case core_plugin_manager::PLUGIN_STATUS_UPGRADE:
947                         $statusclass .= $dependenciesok ? 'label-info' : 'label-warning';
948                         break;
949                     case core_plugin_manager::PLUGIN_STATUS_MISSING:
950                     case core_plugin_manager::PLUGIN_STATUS_DOWNGRADE:
951                     case core_plugin_manager::PLUGIN_STATUS_DELETE:
952                         $statusclass .= 'label-important';
953                         break;
954                     case core_plugin_manager::PLUGIN_STATUS_NODB:
955                     case core_plugin_manager::PLUGIN_STATUS_UPTODATE:
956                         $statusclass .= $dependenciesok ? '' : 'label-warning';
957                         break;
958                 }
959                 $status = html_writer::span(get_string('status_' . $statuscode, 'core_plugin'), $statusclass);
961                 $availableupdates = $plugin->available_updates();
962                 if (!empty($availableupdates) and empty($CFG->disableupdatenotifications)) {
963                     foreach ($availableupdates as $availableupdate) {
964                         $status .= $this->plugin_available_update_info($availableupdate);
965                     }
966                 }
968                 $status = new html_table_cell($sourcelabel.' '.$status);
970                 $requires = new html_table_cell($this->required_column($plugin, $pluginman, $version));
972                 $statusisboring = in_array($statuscode, array(
973                         core_plugin_manager::PLUGIN_STATUS_NODB, core_plugin_manager::PLUGIN_STATUS_UPTODATE));
975                 if ($options['xdep']) {
976                     // we want to see only plugins with failed dependencies
977                     if ($dependenciesok) {
978                         continue;
979                     }
981                 } else if ($statusisboring and $dependenciesok and empty($availableupdates)) {
982                     // no change is going to happen to the plugin - display it only
983                     // if the user wants to see the full list
984                     if (empty($options['full'])) {
985                         continue;
986                     }
987                 }
989                 // ok, the plugin should be displayed
990                 $numofhighlighted[$type]++;
992                 $row->cells = array($displayname, $versiondb, $versiondisk, $requires, $status);
993                 $plugintyperows[] = $row;
994             }
996             if (empty($numofhighlighted[$type]) and empty($options['full'])) {
997                 continue;
998             }
1000             $table->data[] = $header;
1001             $table->data = array_merge($table->data, $plugintyperows);
1002         }
1004         $sumofhighlighted = array_sum($numofhighlighted);
1006         if ($options['xdep']) {
1007             // we do not want to display no heading and links in this mode
1008             $out = '';
1010         } else if ($sumofhighlighted == 0) {
1011             $out  = $this->output->container_start('nonehighlighted', 'plugins-check-info');
1012             $out .= $this->output->heading(get_string('nonehighlighted', 'core_plugin'));
1013             if (empty($options['full'])) {
1014                 $out .= html_writer::link(new moodle_url($this->page->url,
1015                     array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1, 'cache' => 0)),
1016                     get_string('nonehighlightedinfo', 'core_plugin'));
1017             }
1018             $out .= $this->output->container_end();
1020         } else {
1021             $out  = $this->output->container_start('somehighlighted', 'plugins-check-info');
1022             if (empty($options['full'])) {
1023                 $out .= $this->output->heading(get_string('somehighlighted', 'core_plugin', $sumofhighlighted));
1024                 $out .= html_writer::link(new moodle_url($this->page->url,
1025                     array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1, 'cache' => 0)),
1026                     get_string('somehighlightedinfo', 'core_plugin'));
1027             } else {
1028                 $out .= $this->output->heading(get_string('somehighlightedall', 'core_plugin', $sumofhighlighted));
1029                 $out .= html_writer::link(new moodle_url($this->page->url,
1030                     array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 0, 'cache' => 0)),
1031                     get_string('somehighlightedonly', 'core_plugin'));
1032             }
1033             $out .= $this->output->container_end();
1034         }
1036         if ($sumofhighlighted > 0 or $options['full']) {
1037             $out .= html_writer::table($table);
1038         }
1040         return $out;
1041     }
1043     /**
1044      * Formats the information that needs to go in the 'Requires' column.
1045      * @param \core\plugininfo\base $plugin the plugin we are rendering the row for.
1046      * @param core_plugin_manager $pluginman provides data on all the plugins.
1047      * @param string $version
1048      * @return string HTML code
1049      */
1050     protected function required_column(\core\plugininfo\base $plugin, core_plugin_manager $pluginman, $version) {
1051         $requires = array();
1053         if (!empty($plugin->versionrequires)) {
1054             if ($plugin->versionrequires <= $version) {
1055                 $class = 'requires-ok';
1056                 $label = '';
1057             } else {
1058                 $class = 'requires-failed';
1059                 $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'label label-important');
1060             }
1061             $requires[] = html_writer::tag('li',
1062                 html_writer::span(get_string('moodleversion', 'core_plugin', $plugin->versionrequires), 'dep dep-core').' '.$label,
1063                 array('class' => $class));
1064         }
1066         foreach ($plugin->get_other_required_plugins() as $component => $requiredversion) {
1067             $otherplugin = $pluginman->get_plugin_info($component);
1068             $actions = array();
1070             if (is_null($otherplugin)) {
1071                 // The required plugin is not installed.
1072                 $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'label label-important');
1073                 $class = 'requires-failed requires-missing';
1074                 $installurl = new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $component));
1075                 $uploadurl = new moodle_url('/admin/tool/installaddon/');
1076                 $actions[] = html_writer::link($installurl, get_string('dependencyinstall', 'core_plugin'));
1077                 $actions[] = html_writer::link($uploadurl, get_string('dependencyupload', 'core_plugin'));
1079             } else if ($requiredversion != ANY_VERSION and $otherplugin->versiondisk < $requiredversion) {
1080                 // The required plugin is installed but needs to be updated.
1081                 $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'label label-important');
1082                 $class = 'requires-failed requires-outdated';
1083                 if (!$otherplugin->is_standard()) {
1084                     $updateurl = new moodle_url($this->page->url, array('sesskey' => sesskey(), 'fetchupdates' => 1));
1085                     $actions[] = html_writer::link($updateurl, get_string('checkforupdates', 'core_plugin'));
1086                 }
1088             } else {
1089                 // Already installed plugin with sufficient version.
1090                 $label = '';
1091                 $class = 'requires-ok';
1092             }
1094             if ($requiredversion != ANY_VERSION) {
1095                 $str = 'otherpluginversion';
1096             } else {
1097                 $str = 'otherplugin';
1098             }
1100             $requires[] = html_writer::tag('li',
1101                     html_writer::span(get_string($str, 'core_plugin',
1102                             array('component' => $component, 'version' => $requiredversion)), 'dep dep-plugin').' '.$label.
1103                     ' '.html_writer::span(implode(' | ', $actions), 'actions'),
1104                     array('class' => $class));
1105         }
1107         if (!$requires) {
1108             return '';
1109         }
1110         return html_writer::tag('ul', implode("\n", $requires));
1111     }
1113     /**
1114      * Prints an overview about the plugins - number of installed, number of extensions etc.
1115      *
1116      * @param core_plugin_manager $pluginman provides information about the plugins
1117      * @param array $options filtering options
1118      * @return string as usually
1119      */
1120     public function plugins_overview_panel(core_plugin_manager $pluginman, array $options = array()) {
1121         global $CFG;
1123         $plugininfo = $pluginman->get_plugins();
1125         $numtotal = $numdisabled = $numextension = $numupdatable = 0;
1127         foreach ($plugininfo as $type => $plugins) {
1128             foreach ($plugins as $name => $plugin) {
1129                 if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
1130                     continue;
1131                 }
1132                 $numtotal++;
1133                 if ($plugin->is_enabled() === false) {
1134                     $numdisabled++;
1135                 }
1136                 if (!$plugin->is_standard()) {
1137                     $numextension++;
1138                 }
1139                 if (empty($CFG->disableupdatenotifications) and $plugin->available_updates()) {
1140                     $numupdatable++;
1141                 }
1142             }
1143         }
1145         $info = array();
1146         $filter = array();
1147         $somefilteractive = false;
1148         $info[] = html_writer::tag('span', get_string('numtotal', 'core_plugin', $numtotal), array('class' => 'info total'));
1149         $info[] = html_writer::tag('span', get_string('numdisabled', 'core_plugin', $numdisabled), array('class' => 'info disabled'));
1150         $info[] = html_writer::tag('span', get_string('numextension', 'core_plugin', $numextension), array('class' => 'info extension'));
1151         if ($numextension > 0) {
1152             if (empty($options['contribonly'])) {
1153                 $filter[] = html_writer::link(
1154                     new moodle_url($this->page->url, array('contribonly' => 1)),
1155                     get_string('filtercontribonly', 'core_plugin'),
1156                     array('class' => 'filter-item show-contribonly')
1157                 );
1158             } else {
1159                 $filter[] = html_writer::tag('span', get_string('filtercontribonlyactive', 'core_plugin'),
1160                     array('class' => 'filter-item active show-contribonly'));
1161                 $somefilteractive = true;
1162             }
1163         }
1164         if ($numupdatable > 0) {
1165             $info[] = html_writer::tag('span', get_string('numupdatable', 'core_plugin', $numupdatable), array('class' => 'info updatable'));
1166             if (empty($options['updatesonly'])) {
1167                 $filter[] = html_writer::link(
1168                     new moodle_url($this->page->url, array('updatesonly' => 1)),
1169                     get_string('filterupdatesonly', 'core_plugin'),
1170                     array('class' => 'filter-item show-updatesonly')
1171                 );
1172             } else {
1173                 $filter[] = html_writer::tag('span', get_string('filterupdatesonlyactive', 'core_plugin'),
1174                     array('class' => 'filter-item active show-updatesonly'));
1175                 $somefilteractive = true;
1176             }
1177         }
1178         if ($somefilteractive) {
1179             $filter[] = html_writer::link($this->page->url, get_string('filterall', 'core_plugin'), array('class' => 'filter-item show-all'));
1180         }
1182         $output  = $this->output->box(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $info), '', 'plugins-overview-panel');
1184         if (!empty($filter)) {
1185             $output .= $this->output->box(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $filter), '', 'plugins-overview-filter');
1186         }
1188         return $output;
1189     }
1191     /**
1192      * Displays all known plugins and links to manage them
1193      *
1194      * This default implementation renders all plugins into one big table.
1195      *
1196      * @param core_plugin_manager $pluginman provides information about the plugins.
1197      * @param array $options filtering options
1198      * @return string HTML code
1199      */
1200     public function plugins_control_panel(core_plugin_manager $pluginman, array $options = array()) {
1201         global $CFG;
1203         $plugininfo = $pluginman->get_plugins();
1205         // Filter the list of plugins according the options.
1206         if (!empty($options['updatesonly'])) {
1207             $updateable = array();
1208             foreach ($plugininfo as $plugintype => $pluginnames) {
1209                 foreach ($pluginnames as $pluginname => $pluginfo) {
1210                     if (!empty($pluginfo->availableupdates)) {
1211                         foreach ($pluginfo->availableupdates as $pluginavailableupdate) {
1212                             if ($pluginavailableupdate->version > $pluginfo->versiondisk) {
1213                                 $updateable[$plugintype][$pluginname] = $pluginfo;
1214                             }
1215                         }
1216                     }
1217                 }
1218             }
1219             $plugininfo = $updateable;
1220         }
1222         if (!empty($options['contribonly'])) {
1223             $contribs = array();
1224             foreach ($plugininfo as $plugintype => $pluginnames) {
1225                 foreach ($pluginnames as $pluginname => $pluginfo) {
1226                     if (!$pluginfo->is_standard()) {
1227                         $contribs[$plugintype][$pluginname] = $pluginfo;
1228                     }
1229                 }
1230             }
1231             $plugininfo = $contribs;
1232         }
1234         if (empty($plugininfo)) {
1235             return '';
1236         }
1238         $table = new html_table();
1239         $table->id = 'plugins-control-panel';
1240         $table->head = array(
1241             get_string('displayname', 'core_plugin'),
1242             get_string('source', 'core_plugin'),
1243             get_string('version', 'core_plugin'),
1244             get_string('release', 'core_plugin'),
1245             get_string('availability', 'core_plugin'),
1246             get_string('actions', 'core_plugin'),
1247             get_string('notes','core_plugin'),
1248         );
1249         $table->headspan = array(1, 1, 1, 1, 1, 2, 1);
1250         $table->colclasses = array(
1251             'pluginname', 'source', 'version', 'release', 'availability', 'settings', 'uninstall', 'notes'
1252         );
1254         foreach ($plugininfo as $type => $plugins) {
1255             $heading = $pluginman->plugintype_name_plural($type);
1256             $pluginclass = core_plugin_manager::resolve_plugininfo_class($type);
1257             if ($manageurl = $pluginclass::get_manage_url()) {
1258                 $heading = html_writer::link($manageurl, $heading);
1259             }
1260             $header = new html_table_cell(html_writer::tag('span', $heading, array('id'=>'plugin_type_cell_'.$type)));
1261             $header->header = true;
1262             $header->colspan = array_sum($table->headspan);
1263             $header = new html_table_row(array($header));
1264             $header->attributes['class'] = 'plugintypeheader type-' . $type;
1265             $table->data[] = $header;
1267             if (empty($plugins)) {
1268                 $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
1269                 $msg->colspan = array_sum($table->headspan);
1270                 $row = new html_table_row(array($msg));
1271                 $row->attributes['class'] .= 'msg msg-noneinstalled';
1272                 $table->data[] = $row;
1273                 continue;
1274             }
1276             foreach ($plugins as $name => $plugin) {
1277                 $row = new html_table_row();
1278                 $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
1280                 if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
1281                     $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'icon pluginicon'));
1282                 } else {
1283                     $icon = $this->output->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
1284                 }
1285                 $status = $plugin->get_status();
1286                 $row->attributes['class'] .= ' status-'.$status;
1287                 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
1288                     $msg = html_writer::tag('span', get_string('status_missing', 'core_plugin'), array('class' => 'statusmsg'));
1289                 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
1290                     $msg = html_writer::tag('span', get_string('status_new', 'core_plugin'), array('class' => 'statusmsg'));
1291                 } else {
1292                     $msg = '';
1293                 }
1294                 $pluginname  = html_writer::tag('div', $icon . '' . $plugin->displayname . ' ' . $msg, array('class' => 'displayname')).
1295                                html_writer::tag('div', $plugin->component, array('class' => 'componentname'));
1296                 $pluginname  = new html_table_cell($pluginname);
1298                 if ($plugin->is_standard()) {
1299                     $row->attributes['class'] .= ' standard';
1300                     $source = new html_table_cell(get_string('sourcestd', 'core_plugin'));
1301                 } else {
1302                     $row->attributes['class'] .= ' extension';
1303                     $source = new html_table_cell(get_string('sourceext', 'core_plugin'));
1304                 }
1306                 $version = new html_table_cell($plugin->versiondb);
1307                 $release = new html_table_cell($plugin->release);
1309                 $isenabled = $plugin->is_enabled();
1310                 if (is_null($isenabled)) {
1311                     $availability = new html_table_cell('');
1312                 } else if ($isenabled) {
1313                     $row->attributes['class'] .= ' enabled';
1314                     $availability = new html_table_cell(get_string('pluginenabled', 'core_plugin'));
1315                 } else {
1316                     $row->attributes['class'] .= ' disabled';
1317                     $availability = new html_table_cell(get_string('plugindisabled', 'core_plugin'));
1318                 }
1320                 $settingsurl = $plugin->get_settings_url();
1321                 if (!is_null($settingsurl)) {
1322                     $settings = html_writer::link($settingsurl, get_string('settings', 'core_plugin'), array('class' => 'settings'));
1323                 } else {
1324                     $settings = '';
1325                 }
1326                 $settings = new html_table_cell($settings);
1328                 if ($uninstallurl = $pluginman->get_uninstall_url($plugin->component, 'overview')) {
1329                     $uninstall = html_writer::link($uninstallurl, get_string('uninstall', 'core_plugin'));
1330                 } else {
1331                     $uninstall = '';
1332                 }
1333                 $uninstall = new html_table_cell($uninstall);
1335                 $requriedby = $pluginman->other_plugins_that_require($plugin->component);
1336                 if ($requriedby) {
1337                     $requiredby = html_writer::tag('div', get_string('requiredby', 'core_plugin', implode(', ', $requriedby)),
1338                         array('class' => 'requiredby'));
1339                 } else {
1340                     $requiredby = '';
1341                 }
1343                 $updateinfo = '';
1344                 if (empty($CFG->disableupdatenotifications) and is_array($plugin->available_updates())) {
1345                     foreach ($plugin->available_updates() as $availableupdate) {
1346                         $updateinfo .= $this->plugin_available_update_info($availableupdate);
1347                     }
1348                 }
1350                 $notes = new html_table_cell($requiredby.$updateinfo);
1352                 $row->cells = array(
1353                     $pluginname, $source, $version, $release, $availability, $settings, $uninstall, $notes
1354                 );
1355                 $table->data[] = $row;
1356             }
1357         }
1359         return html_writer::table($table);
1360     }
1362     /**
1363      * Helper method to render the information about the available plugin update
1364      *
1365      * The passed objects always provides at least the 'version' property containing
1366      * the (higher) version of the plugin available.
1367      *
1368      * @param \core\update\info $updateinfo information about the available update for the plugin
1369      */
1370     protected function plugin_available_update_info(\core\update\info $updateinfo) {
1372         $boxclasses = 'pluginupdateinfo';
1373         $info = array();
1375         if (isset($updateinfo->release)) {
1376             $info[] = html_writer::tag('span', get_string('updateavailable_release', 'core_plugin', $updateinfo->release),
1377                 array('class' => 'info release'));
1378         }
1380         if (isset($updateinfo->maturity)) {
1381             $info[] = html_writer::tag('span', get_string('maturity'.$updateinfo->maturity, 'core_admin'),
1382                 array('class' => 'info maturity'));
1383             $boxclasses .= ' maturity'.$updateinfo->maturity;
1384         }
1386         if (isset($updateinfo->download)) {
1387             $info[] = html_writer::link($updateinfo->download, get_string('download'), array('class' => 'info download'));
1388         }
1390         if (isset($updateinfo->url)) {
1391             $info[] = html_writer::link($updateinfo->url, get_string('updateavailable_moreinfo', 'core_plugin'),
1392                 array('class' => 'info more'));
1393         }
1395         $box  = $this->output->box_start($boxclasses);
1396         $box .= html_writer::tag('div', get_string('updateavailable', 'core_plugin', $updateinfo->version), array('class' => 'version'));
1397         $box .= $this->output->box(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $info), '');
1399         $deployer = \core\update\deployer::instance();
1400         if ($deployer->initialized()) {
1401             $impediments = $deployer->deployment_impediments($updateinfo);
1402             if (empty($impediments)) {
1403                 $widget = $deployer->make_confirm_widget($updateinfo);
1404                 $box .= $this->output->render($widget);
1405             } else {
1406                 if (isset($impediments['notwritable'])) {
1407                     $box .= $this->output->help_icon('notwritable', 'core_plugin', get_string('notwritable', 'core_plugin'));
1408                 }
1409                 if (isset($impediments['notdownloadable'])) {
1410                     $box .= $this->output->help_icon('notdownloadable', 'core_plugin', get_string('notdownloadable', 'core_plugin'));
1411                 }
1412             }
1413         }
1415         $box .= $this->output->box_end();
1417         return $box;
1418     }
1420     /**
1421      * This function will render one beautiful table with all the environmental
1422      * configuration and how it suits Moodle needs.
1423      *
1424      * @param boolean $result final result of the check (true/false)
1425      * @param environment_results[] $environment_results array of results gathered
1426      * @return string HTML to output.
1427      */
1428     public function environment_check_table($result, $environment_results) {
1429         global $CFG;
1431         // Table headers
1432         $servertable = new html_table();//table for server checks
1433         $servertable->head  = array(
1434             get_string('name'),
1435             get_string('info'),
1436             get_string('report'),
1437             get_string('plugin'),
1438             get_string('status'),
1439         );
1440         $servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'leftalign plugin', 'centeralign status');
1441         $servertable->attributes['class'] = 'admintable environmenttable generaltable';
1442         $servertable->id = 'serverstatus';
1444         $serverdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
1446         $othertable = new html_table();//table for custom checks
1447         $othertable->head  = array(
1448             get_string('info'),
1449             get_string('report'),
1450             get_string('plugin'),
1451             get_string('status'),
1452         );
1453         $othertable->colclasses = array('aligncenter info', 'alignleft report', 'alignleft plugin', 'aligncenter status');
1454         $othertable->attributes['class'] = 'admintable environmenttable generaltable';
1455         $othertable->id = 'otherserverstatus';
1457         $otherdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
1459         // Iterate over each environment_result
1460         $continue = true;
1461         foreach ($environment_results as $environment_result) {
1462             $errorline   = false;
1463             $warningline = false;
1464             $stringtouse = '';
1465             if ($continue) {
1466                 $type = $environment_result->getPart();
1467                 $info = $environment_result->getInfo();
1468                 $status = $environment_result->getStatus();
1469                 $plugin = $environment_result->getPluginName();
1470                 $error_code = $environment_result->getErrorCode();
1471                 // Process Report field
1472                 $rec = new stdClass();
1473                 // Something has gone wrong at parsing time
1474                 if ($error_code) {
1475                     $stringtouse = 'environmentxmlerror';
1476                     $rec->error_code = $error_code;
1477                     $status = get_string('error');
1478                     $errorline = true;
1479                     $continue = false;
1480                 }
1482                 if ($continue) {
1483                     if ($rec->needed = $environment_result->getNeededVersion()) {
1484                         // We are comparing versions
1485                         $rec->current = $environment_result->getCurrentVersion();
1486                         if ($environment_result->getLevel() == 'required') {
1487                             $stringtouse = 'environmentrequireversion';
1488                         } else {
1489                             $stringtouse = 'environmentrecommendversion';
1490                         }
1492                     } else if ($environment_result->getPart() == 'custom_check') {
1493                         // We are checking installed & enabled things
1494                         if ($environment_result->getLevel() == 'required') {
1495                             $stringtouse = 'environmentrequirecustomcheck';
1496                         } else {
1497                             $stringtouse = 'environmentrecommendcustomcheck';
1498                         }
1500                     } else if ($environment_result->getPart() == 'php_setting') {
1501                         if ($status) {
1502                             $stringtouse = 'environmentsettingok';
1503                         } else if ($environment_result->getLevel() == 'required') {
1504                             $stringtouse = 'environmentmustfixsetting';
1505                         } else {
1506                             $stringtouse = 'environmentshouldfixsetting';
1507                         }
1509                     } else {
1510                         if ($environment_result->getLevel() == 'required') {
1511                             $stringtouse = 'environmentrequireinstall';
1512                         } else {
1513                             $stringtouse = 'environmentrecommendinstall';
1514                         }
1515                     }
1517                     // Calculate the status value
1518                     if ($environment_result->getBypassStr() != '') {            //Handle bypassed result (warning)
1519                         $status = get_string('bypassed');
1520                         $warningline = true;
1521                     } else if ($environment_result->getRestrictStr() != '') {   //Handle restricted result (error)
1522                         $status = get_string('restricted');
1523                         $errorline = true;
1524                     } else {
1525                         if ($status) {                                          //Handle ok result (ok)
1526                             $status = get_string('ok');
1527                         } else {
1528                             if ($environment_result->getLevel() == 'optional') {//Handle check result (warning)
1529                                 $status = get_string('check');
1530                                 $warningline = true;
1531                             } else {                                            //Handle error result (error)
1532                                 $status = get_string('check');
1533                                 $errorline = true;
1534                             }
1535                         }
1536                     }
1537                 }
1539                 // Build the text
1540                 $linkparts = array();
1541                 $linkparts[] = 'admin/environment';
1542                 $linkparts[] = $type;
1543                 if (!empty($info)){
1544                    $linkparts[] = $info;
1545                 }
1546                 // Plugin environments do not have docs pages yet.
1547                 if (empty($CFG->docroot) or $environment_result->plugin) {
1548                     $report = get_string($stringtouse, 'admin', $rec);
1549                 } else {
1550                     $report = $this->doc_link(join($linkparts, '/'), get_string($stringtouse, 'admin', $rec));
1551                 }
1553                 // Format error or warning line
1554                 if ($errorline || $warningline) {
1555                     $messagetype = $errorline? 'error':'warn';
1556                 } else {
1557                     $messagetype = 'ok';
1558                 }
1559                 $status = '<span class="'.$messagetype.'">'.$status.'</span>';
1560                 // Here we'll store all the feedback found
1561                 $feedbacktext = '';
1562                 // Append the feedback if there is some
1563                 $feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(), $messagetype);
1564                 //Append the bypass if there is some
1565                 $feedbacktext .= $environment_result->strToReport($environment_result->getBypassStr(), 'warn');
1566                 //Append the restrict if there is some
1567                 $feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(), 'error');
1569                 $report .= $feedbacktext;
1571                 // Add the row to the table
1572                 if ($environment_result->getPart() == 'custom_check'){
1573                     $otherdata[$messagetype][] = array ($info, $report, $plugin, $status);
1574                 } else {
1575                     $serverdata[$messagetype][] = array ($type, $info, $report, $plugin, $status);
1576                 }
1577             }
1578         }
1580         //put errors first in
1581         $servertable->data = array_merge($serverdata['error'], $serverdata['warn'], $serverdata['ok']);
1582         $othertable->data = array_merge($otherdata['error'], $otherdata['warn'], $otherdata['ok']);
1584         // Print table
1585         $output = '';
1586         $output .= $this->heading(get_string('serverchecks', 'admin'));
1587         $output .= html_writer::table($servertable);
1588         if (count($othertable->data)){
1589             $output .= $this->heading(get_string('customcheck', 'admin'));
1590             $output .= html_writer::table($othertable);
1591         }
1593         // Finally, if any error has happened, print the summary box
1594         if (!$result) {
1595             $output .= $this->box(get_string('environmenterrortodo', 'admin'), 'environmentbox errorbox');
1596         }
1598         return $output;
1599     }
1601     /**
1602      * Render a simple page for providing the upgrade key.
1603      *
1604      * @param moodle_url|string $url
1605      * @return string
1606      */
1607     public function upgradekey_form_page($url) {
1609         $output = '';
1610         $output .= $this->header();
1611         $output .= $this->container_start('upgradekeyreq');
1612         $output .= $this->heading(get_string('upgradekeyreq', 'core_admin'));
1613         $output .= html_writer::start_tag('form', array('method' => 'POST', 'action' => $url));
1614         $output .= html_writer::empty_tag('input', array('name' => 'upgradekey', 'type' => 'password'));
1615         $output .= html_writer::empty_tag('input', array('value' => get_string('submit'), 'type' => 'submit'));
1616         $output .= html_writer::end_tag('form');
1617         $output .= $this->container_end();
1618         $output .= $this->footer();
1620         return $output;
1621     }