MDL-38509 Implement the ZIP package validation page
authorDavid Mudrák <david@moodle.com>
Fri, 22 Mar 2013 16:53:55 +0000 (17:53 +0100)
committerDavid Mudrák <david@moodle.com>
Thu, 28 Mar 2013 10:54:06 +0000 (11:54 +0100)
The script validate.php expects a ZIP file stored in a temporary
location. It extracts the ZIP (optionally renaming the root directory)
and executes the validator. Then it renders the validator log messages
and continue buttons.

admin/tool/installaddon/classes/installfromzip_form.php
admin/tool/installaddon/renderer.php
admin/tool/installaddon/settings.php
admin/tool/installaddon/styles.css
admin/tool/installaddon/validate.php [new file with mode: 0644]

index 9942679..18552fa 100644 (file)
@@ -43,6 +43,9 @@ class tool_installaddon_installfromzip extends moodleform {
         $mform = $this->_form;
         $installer = $this->_customdata['installer'];
 
+        $mform->addElement('header', 'general', get_string('installfromzip', 'tool_installaddon'));
+        $mform->addHelpButton('general', 'installfromzip', 'tool_installaddon');
+
         $options = $installer->get_plugin_types_menu();
         $mform->addElement('select', 'plugintype', get_string('installfromziptype', 'tool_installaddon'), $options,
             array('id' => 'tool_installaddon_installfromzip_plugintype'));
@@ -58,6 +61,11 @@ class tool_installaddon_installfromzip extends moodleform {
         $mform->addHelpButton('zipfile', 'installfromzipfile', 'tool_installaddon');
         $mform->addRule('zipfile', null, 'required', null, 'client');
 
+        $mform->addElement('text', 'rootdir', get_string('installfromziprootdir', 'tool_installaddon'));
+        $mform->addHelpButton('rootdir', 'installfromziprootdir', 'tool_installaddon');
+        $mform->setType('rootdir', PARAM_PLUGIN);
+        $mform->setAdvanced('rootdir');
+
         $mform->addElement('checkbox', 'acknowledgement', get_string('acknowledgement', 'tool_installaddon'),
             ' '.get_string('acknowledgementtext', 'tool_installaddon'));
         $mform->addRule('acknowledgement', get_string('acknowledgementmust', 'tool_installaddon'), 'required', null, 'client');
index e670c6d..0cc273d 100644 (file)
@@ -37,6 +37,9 @@ class tool_installaddon_renderer extends plugin_renderer_base {
     /** @var tool_installaddon_installer */
     protected $installer = null;
 
+    /** @var tool_installaddon_validator */
+    protected $validator = null;
+
     /**
      * Sets the tool_installaddon_installer instance being used.
      *
@@ -51,6 +54,20 @@ class tool_installaddon_renderer extends plugin_renderer_base {
         }
     }
 
+    /**
+     * Sets the tool_installaddon_validator instance being used.
+     *
+     * @throws coding_exception if the validator has been already set
+     * @param tool_installaddon_validator $validator
+     */
+    public function set_validator_instance(tool_installaddon_validator $validator) {
+        if (is_null($this->validator)) {
+            $this->validator = $validator;
+        } else {
+            throw new coding_exception('Attempting to reset the validator instance.');
+        }
+    }
+
     /**
      * Defines the index page layout
      *
@@ -58,6 +75,10 @@ class tool_installaddon_renderer extends plugin_renderer_base {
      */
     public function index_page() {
 
+        if (is_null($this->installer)) {
+            throw new coding_exception('Installer instance has not been set.');
+        }
+
         $permcheckurl = new moodle_url('/admin/tool/installaddon/permcheck.php');
         $this->page->requires->yui_module('moodle-tool_installaddon-permcheck', 'M.tool_installaddon.permcheck.init',
             array(array('permcheckurl' => $permcheckurl->out())));
@@ -73,6 +94,33 @@ class tool_installaddon_renderer extends plugin_renderer_base {
         return $out;
     }
 
+    /**
+     * Defines the validation results page layout
+     *
+     * @return string
+     */
+    public function validation_page() {
+
+        if (is_null($this->installer)) {
+            throw new coding_exception('Installer instance has not been set.');
+        }
+
+        if (is_null($this->validator)) {
+            throw new coding_exception('Validator instance has not been set.');
+        }
+
+        $out = $this->output->header();
+        $out .= $this->validation_page_heading();
+        $out .= $this->validation_page_messages();
+        $out .= $this->validation_page_continue();
+        $out .= $this->output->footer();
+
+        return $out;
+
+    }
+
+    // End of the external API /////////////////////////////////////////////////
+
     /**
      * Renders the index page heading
      *
@@ -117,4 +165,116 @@ class tool_installaddon_renderer extends plugin_renderer_base {
 
         return $out;
     }
+
+    /**
+     * Renders the page title and the overall validation verdict
+     *
+     * @return string
+     */
+    protected function validation_page_heading() {
+
+        $heading = $this->output->heading(get_string('validation', 'tool_installaddon'));
+
+        if ($this->validator->get_result()) {
+            $status = $this->output->container(
+                html_writer::span(get_string('validationresult1', 'tool_installaddon'), 'verdict').
+                    $this->output->help_icon('validationresult1', 'tool_installaddon'),
+                array('validationresult', 'success')
+            );
+        } else {
+            $status = $this->output->container(
+                html_writer::span(get_string('validationresult0', 'tool_installaddon'), 'verdict').
+                    $this->output->help_icon('validationresult0', 'tool_installaddon'),
+                array('validationresult', 'failure')
+            );
+        }
+
+        return $heading . $status;
+    }
+
+    /**
+     * Renders validation log messages.
+     *
+     * @return string
+     */
+    protected function validation_page_messages() {
+
+        $validator = $this->validator; // We need this to be able to use their constants.
+        $messages = $validator->get_messages();
+
+        if (empty($messages)) {
+            return '';
+        }
+
+        $table = new html_table();
+        $table->attributes['class'] = 'validationmessages generaltable';
+        $table->head = array(
+            get_string('validationresultstatus', 'tool_installaddon'),
+            get_string('validationresultmsg', 'tool_installaddon'),
+            get_string('validationresultinfo', 'tool_installaddon')
+        );
+        $table->colclasses = array('msgstatus', 'msgtext', 'msginfo');
+
+        $stringman = get_string_manager();
+
+        foreach ($messages as $message) {
+
+            if ($message->level === $validator::DEBUG and !debugging()) {
+                continue;
+            }
+
+            $msgstatus = get_string('validationmsglevel_'.$message->level, 'tool_installaddon');
+            $msgtext = $msgtext = s($message->msgcode);
+            if (is_null($message->addinfo)) {
+                $msginfo = '';
+            } else {
+                $msginfo = html_writer::tag('pre', s(print_r($message->addinfo, true)));
+            }
+            $msghelp = '';
+
+            // Replace the message code with the string if it is defined.
+            if ($stringman->string_exists('validationmsg_'.$message->msgcode, 'tool_installaddon')) {
+                $msgtext = get_string('validationmsg_'.$message->msgcode, 'tool_installaddon');
+                // And check for the eventual help, too.
+                if ($stringman->string_exists('validationmsg_'.$message->msgcode.'_help', 'tool_installaddon')) {
+                    $msghelp = $this->output->help_icon('validationmsg_'.$message->msgcode, 'tool_installaddon');
+                }
+            }
+
+            // Re-format the message info using a string if it is define.
+            if (!is_null($message->addinfo) and $stringman->string_exists('validationmsg_'.$message->msgcode.'_info', 'tool_installaddon')) {
+                $msginfo = get_string('validationmsg_'.$message->msgcode.'_info', 'tool_installaddon', $message->addinfo);
+            }
+
+            $row = new html_table_row(array($msgstatus, $msgtext.$msghelp, $msginfo));
+            $row->attributes['class'] = 'level-'.$message->level.' '.$message->msgcode;
+
+            $table->data[] = $row;
+        }
+
+        return html_writer::table($table);
+    }
+
+    /**
+     * Renders widgets to continue from the validation results page
+     *
+     * @return string
+     */
+    protected function validation_page_continue() {
+
+        $conturl = $this->validator->get_continue_url();
+        if (is_null($conturl)) {
+            $contbutton = '';
+        } else {
+            $contbutton = $this->output->single_button(
+                $conturl, get_string('installaddon', 'tool_installaddon'), 'post',
+                array('class' => 'singlebutton continuebutton'));
+        }
+
+        $cancelbutton = $this->output->single_button(
+            new moodle_url('/admin/tool/installaddon/index.php'), get_string('cancel', 'core'), 'get',
+            array('class' => 'singlebutton cancelbutton'));
+
+        return $this->output->container($cancelbutton.$contbutton, 'postvalidationbuttons');
+    }
 }
index 326f030..0c03c73 100644 (file)
@@ -29,6 +29,11 @@ if ($hassiteconfig and empty($CFG->disableonclickaddoninstall)) {
 
     $ADMIN->add('modules', new admin_externalpage('tool_installaddon_index',
         get_string('installaddons', 'tool_installaddon'),
-        "$CFG->wwwroot/$CFG->admin/tool/installaddon/"));
+        "$CFG->wwwroot/$CFG->admin/tool/installaddon/index.php"));
 
+    $ADMIN->add('modules', new admin_externalpage('tool_installaddon_validate',
+        get_string('validation', 'tool_installaddon'),
+        "$CFG->wwwroot/$CFG->admin/tool/installaddon/validate.php",
+        'moodle/site:config',
+        true));
 }
index 3de50f3..05155ca 100644 (file)
 #page-admin-tool-installaddon-index #installfromrepobox .singlebutton input[type=submit] {
     padding: 1em;
 }
+
+#page-admin-tool-installaddon-validate .validationresult {
+    margin: 2em auto;
+    text-align: center;
+}
+
+#page-admin-tool-installaddon-validate .validationresult .verdict {
+    margin: 0em 0.5em;
+    padding: 0.5em;
+    border: 2px solid;
+    -webkit-border-radius: 5px;
+    -moz-border-radius: 5px;
+    border-radius: 5px;
+    font-weight: bold;
+}
+
+#page-admin-tool-installaddon-validate .validationresult.success .verdict {
+    background-color: #e7f1c3;
+    border-color: #aaeeaa;
+}
+
+#page-admin-tool-installaddon-validate .validationresult.failure .verdict {
+    background-color: #ffd3d9;
+    border-color: #eeaaaa;
+}
+
+#page-admin-tool-installaddon-validate .validationmessages {
+    margin: 0px auto;
+}
+
+#page-admin-tool-installaddon-validate .validationmessages .level-error .msgstatus {
+    background-color: #ffd3d9;
+}
+
+#page-admin-tool-installaddon-validate .validationmessages .level-warning .msgstatus {
+    background-color: #f3f2aa;
+}
+
+#page-admin-tool-installaddon-validate .validationmessages .level-info .msgstatus {
+    background-color: #e7f1c3;
+}
+
+#page-admin-tool-installaddon-validate .validationmessages .level-debug .msgstatus {
+    background-color: #d2ebff;
+}
+
+#page-admin-tool-installaddon-validate .postvalidationbuttons {
+    text-align: center;
+    margin: 1em auto;
+}
+
+#page-admin-tool-installaddon-validate .postvalidationbuttons .singlebutton {
+    display: inline-block;
+    margin: 1em 1em;
+}
diff --git a/admin/tool/installaddon/validate.php b/admin/tool/installaddon/validate.php
new file mode 100644 (file)
index 0000000..2fc66cf
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * The ZIP package validation.
+ *
+ * @package     tool_installaddon
+ * @copyright   2013 David Mudrak <david@moodle.com>
+ * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require(dirname(__FILE__) . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/filelib.php');
+require_once(dirname(__FILE__).'/classes/installer.php');
+require_once(dirname(__FILE__).'/classes/validator.php');
+
+navigation_node::override_active_url(new moodle_url('/admin/tool/installaddon/index.php'));
+admin_externalpage_setup('tool_installaddon_validate');
+
+if (!empty($CFG->disableonclickaddoninstall)) {
+    notice(get_string('featuredisabled', 'tool_installaddon'));
+}
+
+require_sesskey();
+
+$jobid = required_param('jobid', PARAM_ALPHANUM);
+$zipfilename = required_param('zip', PARAM_FILE);
+$plugintype = required_param('type', PARAM_ALPHANUMEXT);
+$rootdir = optional_param('rootdir', '', PARAM_PLUGIN);
+
+$zipfilepath = $CFG->tempdir.'/tool_installaddon/'.$jobid.'/source/'.$zipfilename;
+if (!file_exists($zipfilepath)) {
+    redirect(new moodle_url('/admin/tool/installaddon/index.php'),
+        get_string('invaliddata', 'core_error'));
+}
+
+$installer = tool_installaddon_installer::instance();
+
+// Extract the ZIP contents.
+fulldelete($CFG->tempdir.'/tool_installaddon/'.$jobid.'/contents');
+$zipcontentpath = make_temp_directory('tool_installaddon/'.$jobid.'/contents');
+$zipcontentfiles = $installer->extract_installfromzip_file($zipfilepath, $zipcontentpath, $rootdir);
+
+// Validate the contents of the plugin ZIP file.
+$validator = tool_installaddon_validator::instance($zipcontentpath, $zipcontentfiles);
+$validator->assert_plugin_type($plugintype);
+$validator->assert_moodle_version($CFG->version);
+$result = $validator->execute();
+
+if ($result) {
+    $validator->set_continue_url(new moodle_url('/admin/tool/installaddon/deploy.php', array(
+        'sesskey' => sesskey(),
+        'jobid' => $jobid,
+        'type' => $plugintype,
+        'name' => $validator->get_rootdir())));
+
+} else {
+    fulldelete($CFG->tempdir.'/tool_installaddon/'.$jobid);
+}
+
+// Display the validation results.
+$output = $PAGE->get_renderer('tool_installaddon');
+$output->set_installer_instance($installer);
+$output->set_validator_instance($validator);
+echo $output->validation_page();