MDL-32895: Improvements to assignment upgrade tool for large numbers of assignments.
authorDamyon Wiese <damyon.wiese@netspot.com.au>
Thu, 10 May 2012 03:54:46 +0000 (11:54 +0800)
committerDamyon Wiese <damyon.wiese@netspot.com.au>
Mon, 14 May 2012 04:53:21 +0000 (12:53 +0800)
    * Form to control the perpage variable for the upgradable assignments table.
    * Set timeout and increase memory limit for batch upgrades
    * Output/renderer pages to the upgrade progress is progressively displayed
    * Cleanup of relative includes in assignmentupgrade tool
    * More verbose errors reported for failed upgrades

13 files changed:
admin/tool/assignmentupgrade/batchupgrade.php
admin/tool/assignmentupgrade/index.php
admin/tool/assignmentupgrade/lang/en/tool_assignmentupgrade.php
admin/tool/assignmentupgrade/listnotupgraded.php
admin/tool/assignmentupgrade/locallib.php
admin/tool/assignmentupgrade/module.js
admin/tool/assignmentupgrade/paginationform.php [new file with mode: 0644]
admin/tool/assignmentupgrade/renderer.php
admin/tool/assignmentupgrade/styles.css
admin/tool/assignmentupgrade/upgradableassignmentstable.php
admin/tool/assignmentupgrade/upgradesingle.php
admin/tool/assignmentupgrade/upgradesingleconfirm.php
mod/assign/upgradelib.php

index 20ebf5c..a8d8ec3 100644 (file)
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+define('NO_OUTPUT_BUFFERING', true);
+
 require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentstable.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentsbatchform.php');
 require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentstable.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
 
 require_sesskey();
 
 // admin_externalpage_setup calls require_login and checks moodle/site:config
 admin_externalpage_setup('assignmentupgrade', '', array(), tool_assignmentupgrade_url('batchupgrade'));
+
+
+$PAGE->set_pagelayout('maintenance'); 
 $PAGE->navbar->add(get_string('batchupgrade', 'tool_assignmentupgrade'));
 
 $renderer = $PAGE->get_renderer('tool_assignmentupgrade');
@@ -41,7 +46,26 @@ if (!$confirm) {
     print_error('invalidrequest');
     die();
 }
-$result = tool_assignmentupgrade_upgrade_multiple_assignments(optional_param('upgradeall', 0, PARAM_BOOL),
-                                                explode(',', optional_param('selected', '', PARAM_TEXT)));
+raise_memory_limit(MEMORY_EXTRA);
+session_get_instance()->write_close(); // release session
+
+echo $renderer->header();
+echo $renderer->heading(get_string('batchupgrade', 'tool_assignmentupgrade'));
+
+$current = 0;
+if (optional_param('upgradeall', false, PARAM_BOOL)) {
+    $assignmentids = tool_assignmentupgrade_load_all_upgradable_assignmentids();
+} else {
+    $assignmentids = explode(',', optional_param('selected', '', PARAM_TEXT));
+}
+$total = count($assignmentids);
+
+foreach ($assignmentids as $assignmentid) {
+    list($summary, $success, $log) = tool_assignmentupgrade_upgrade_assignment($assignmentid);
+    $current += 1;
+    echo $renderer->heading(get_string('upgradeprogress', 'tool_assignmentupgrade', array('current'=>$current, 'total'=>$total)), 3);
+    echo $renderer->convert_assignment_result($summary, $success, $log);
+}
 
-echo $renderer->convert_multiple_assignments_result($result);
+echo $renderer->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
+echo $renderer->footer();
index bb7ff49..f4cd179 100644 (file)
@@ -34,8 +34,8 @@
  */
 
 require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
 require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
 
 // admin_externalpage_setup calls require_login and checks moodle/site:config
 admin_externalpage_setup('assignmentupgrade');
@@ -47,4 +47,4 @@ $actions = array();
 $header = get_string('pluginname', 'tool_assignmentupgrade');
 $actions[] = tool_assignmentupgrade_action::make('listnotupgraded');
 
-echo $renderer->index_page($header, $actions);
\ No newline at end of file
+echo $renderer->index_page($header, $actions);
index 3b3734b..e9a61dc 100644 (file)
@@ -26,6 +26,7 @@ $string['areyousure'] = 'Are you sure?';
 $string['areyousuremessage'] = 'Are you sure you want to upgrade the assignment "{$a->name}"?';
 $string['assignmentid'] = 'Assignment ID';
 $string['assignmentnotfound'] = 'Assignment could not be found (id={$a})';
+$string['assignmentsperpage'] = 'Assignments per page';
 $string['assignmenttype'] = 'Assignment type';
 $string['backtoindex'] = 'Back to index';
 $string['batchoperations'] = 'Batch operations';
@@ -43,6 +44,7 @@ $string['pluginname'] = 'Assignment upgrade helper';
 $string['select'] = 'Select';
 $string['submissions'] = 'Submissions';
 $string['supported'] = 'Upgrade';
+$string['updatetable'] = 'Update table';
 $string['unknown'] = 'Unknown';
 $string['upgradeassignmentsummary'] = 'Upgrade assignment: {$a->name} (Course: {$a->shortname})';
 $string['upgradeassignmentsuccess'] = 'Result: Upgrade successful';
@@ -52,5 +54,6 @@ $string['upgradeselected'] = 'Upgrade selected assignments';
 $string['upgradeselectedcount'] = 'Upgrade {$a} selected assignments?';
 $string['upgradeall'] = 'Upgrade all assignments';
 $string['upgradeallconfirm'] = 'Upgrade all assignments?';
+$string['upgradeprogress'] = 'Upgrade assignment {$a->current} of {$a->total}';
 $string['upgradesingle'] = 'Upgrade single assignment';
 $string['viewcourse'] = 'View the course with the converted assignment';
index 37605a5..b03883a 100644 (file)
  */
 
 require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentstable.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentsbatchform.php');
 require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentstable.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/paginationform.php');
 
 // admin_externalpage_setup calls require_login and checks moodle/site:config
 admin_externalpage_setup('assignmentupgrade', '', array(), tool_assignmentupgrade_url('listnotupgraded'));
@@ -34,16 +35,26 @@ $PAGE->navbar->add(get_string('listnotupgraded', 'tool_assignmentupgrade'));
 
 $renderer = $PAGE->get_renderer('tool_assignmentupgrade');
 
-$perpage = get_user_preferences('tool_assignmentupgrade_perpage', 5);
+$perpage = optional_param('perpage', 0, PARAM_INT);
+if (!$perpage) {
+    $perpage = get_user_preferences('tool_assignmentupgrade_perpage', 100);
+} else {
+    set_user_preference('tool_assignmentupgrade_perpage', $perpage);
+}
 $assignments = new tool_assignmentupgrade_assignments_table($perpage);
 
 $batchform = new tool_assignmentupgrade_batchoperations_form();
 $data = $batchform->get_data();
+
 if ($data && $data->selectedassignments != '' || $data && isset($data->upgradeall)) {
     require_sesskey();
     echo $renderer->confirm_batch_operation_page($data);
 } else {
-    echo $renderer->assignment_list_page($assignments, $batchform);
+    $paginationform = new tool_assignmentupgrade_pagination_form();
+    $pagedata = new stdClass();
+    $pagedata->perpage = $perpage;
+    $paginationform->set_data($pagedata);
+    echo $renderer->assignment_list_page($assignments, $batchform, $paginationform);
 }
 
 
index 5b81485..6ea1883 100644 (file)
@@ -170,54 +170,33 @@ function tool_assignmentupgrade_load_all_upgradable_assignmentids() {
 
 
 /**
- * Convert a list of assignments from the old format to the new one.
- * @param bool $upgradeall - Upgrade all possible assignments
- * @param array $assignmentids An array of assignment ids to upgrade
- * @return array of $entry['assignmentsummary' => (result from tool_assignmentupgrade_get_assignment)
- *                  $entry['success'] => boolean
- *                  $entry['log'] => string - upgrade log
+ * Upgrade a single assignment. This is used by both upgrade single and upgrade batch
+ *
+ * @param int $assignmentid - The assignment id to upgrade
+ * @return array(string, boolean, string) -
+ *                  The array contains
+ *                      - the assignment summary (returned by tool_assignmentupgrade_get_assignment)
+ *                      - success
+ *                      - the upgrade log
  */
-function tool_assignmentupgrade_upgrade_multiple_assignments($upgradeall, $assignmentids) {
+function tool_assignmentupgrade_upgrade_assignment($assignmentid) {
     global $CFG;
-    require_once($CFG->dirroot . '/mod/assign/locallib.php');
     require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
-    $upgrades = array();
-
-    if ($upgradeall) {
-        $assignmentids = tool_assignmentupgrade_load_all_upgradable_assignmentids();
-    }
 
     $assignment_upgrader = new assign_upgrade_manager();
-    foreach ($assignmentids as $assignmentid) {
-        $info = tool_assignmentupgrade_get_assignment($assignmentid);
-        if ($info) {
-            $log = '';
-            $success = $assignment_upgrader->upgrade_assignment($assignmentid, $log);
-        } else {
-            $success = false;
-            $log = get_string('assignmentnotfound', 'tool_assignmentupgrade', $assignmentid);
-            $info = new stdClass();
-            $info->name = get_string('unknown', 'tool_assignmentupgrade');
-            $info->shortname = get_string('unknown', 'tool_assignmentupgrade');
-        }
-
-        $upgrades[] = array('assignmentsummary'=>$info, 'success'=>$success, 'log'=>$log);
+    $info = tool_assignmentupgrade_get_assignment($assignmentid);
+    if ($info) {
+        $log = '';
+        $success = $assignment_upgrader->upgrade_assignment($assignmentid, $log);
+    } else {
+        $success = false;
+        $log = get_string('assignmentnotfound', 'tool_assignmentupgrade', $assignmentid);
+        $info = new stdClass();
+        $info->name = get_string('unknown', 'tool_assignmentupgrade');
+        $info->shortname = get_string('unknown', 'tool_assignmentupgrade');
     }
-    return $upgrades;
-}
 
-/**
- * Convert a single assignment from the old format to the new one.
- * @param stdClass $assignmentinfo An object containing information about this class
- * @param string $log This gets appended to with the details of the conversion process
- * @return boolean This is the overall result (true/false)
- */
-function tool_assignmentupgrade_upgrade_assignment($assignmentinfo, &$log) {
-    global $CFG;
-    require_once($CFG->dirroot . '/mod/assign/locallib.php');
-    require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
-    $assignment_upgrader = new assign_upgrade_manager();
-    return $assignment_upgrader->upgrade_assignment($assignmentinfo->id, $log);
+    return array($info, $success, $log);
 }
 
 /**
index 829f99a..edee839 100644 (file)
@@ -61,6 +61,11 @@ M.tool_assignmentupgrade = {
             }
         });
 
+        var perpage = Y.one('#id_perpage');
+        perpage.on('change', function(e) {
+            window.onbeforeunload = null;
+            Y.one('.tool_assignmentupgrade_paginationform form').submit();
+        });
 
     }
 }
diff --git a/admin/tool/assignmentupgrade/paginationform.php b/admin/tool/assignmentupgrade/paginationform.php
new file mode 100644 (file)
index 0000000..3efb8d4
--- /dev/null
@@ -0,0 +1,59 @@
+<?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/>.
+
+/**
+ * This file contains the forms to create and edit an instance of this module
+ *
+ * @package   tool_assignmentupgrade
+ * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
+
+
+/** Include formslib.php */
+require_once ($CFG->libdir.'/formslib.php');
+
+/**
+ * Assignment upgrade table display options
+ *
+ * @package   tool_assignmentupgrade
+ * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_assignmentupgrade_pagination_form extends moodleform {
+    /**
+     * Define this form - called from the parent constructor
+     */
+    function definition() {
+        $mform = $this->_form;
+        $instance = $this->_customdata;
+
+        $mform->addElement('header', 'general', get_string('assignmentsperpage', 'tool_assignmentupgrade'));
+        // visible elements
+        $options = array(10=>'10', 20=>'20', 50=>'50', 100=>'100');
+        $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options);
+
+        // hidden params
+        $mform->addElement('hidden', 'action', 'saveoptions');
+        $mform->setType('action', PARAM_ALPHA);
+
+        // buttons
+        $this->add_action_buttons(false, get_string('updatetable', 'tool_assignmentupgrade'));
+    }
+}
+
index 16c013c..7c64f7f 100644 (file)
@@ -112,9 +112,10 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
      * Render the list of assignments that still need to be upgraded page.
      * @param tool_assignmentupgrade_assignments_table $assignments of data about assignments.
      * @param tool_assignmentupgrade_batchoperations_form $batchform Submitted form with list of assignments to upgrade
+     * @param tool_assignmentupgrade_pagination_form $paginationform Form which contains the preferences for paginating the table
      * @return string html to output.
      */
-    public function assignment_list_page(tool_assignmentupgrade_assignments_table $assignments, tool_assignmentupgrade_batchoperations_form $batchform) {
+    public function assignment_list_page(tool_assignmentupgrade_assignments_table $assignments, tool_assignmentupgrade_batchoperations_form $batchform, tool_assignmentupgrade_pagination_form $paginationform) {
         $output = '';
         $output .= $this->header();
         $this->page->requires->js_init_call('M.tool_assignmentupgrade.init_upgrade_table', array());
@@ -126,6 +127,10 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
 
         $output .= $this->container_start('tool_assignmentupgrade_upgradetable');
 
+        $output .= $this->container_start('tool_assignmentupgrade_paginationform');
+        $output .= $this->moodleform($paginationform);
+        $output .= $this->container_end();
+
         $output .= $this->flexible_table($assignments, $assignments->get_rows_per_page(), true);
         $output .= $this->container_end();
 
@@ -140,43 +145,6 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
         return $output;
     }
 
-    /**
-     * Render the result of an assignment conversion
-     * @param array $assignments - An array of arrays with keys $entry['assignmentsummary', 'success', 'log']
-     *                            See convert_assignment_result for more description of these keys.
-     * @return string html to output.
-     */
-    public function convert_multiple_assignments_result($assignments) {
-        $output = '';
-        $output .= $this->header();
-        $output .= $this->heading(get_string('batchupgrade', 'tool_assignmentupgrade'));
-
-        foreach ($assignments as $assignment) {
-            $assignmentsummary = $assignment['assignmentsummary'];
-            $success = $assignment['success'];
-            $log = $assignment['log'];
-
-            $output .= $this->heading(get_string('upgradeassignmentsummary', 'tool_assignmentupgrade', $assignmentsummary), 5);
-            if ($success) {
-                $output .= $this->container(get_string('upgradeassignmentsuccess', 'tool_assignmentupgrade'));
-
-            } else {
-                $output .= $this->container(get_string('upgradeassignmentfailed', 'tool_assignmentupgrade', $assignment));
-            }
-            if (isset($assignmentsummary->courseid)) {
-                $output .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$assignmentsummary->courseid)) ,get_string('viewcourse', 'tool_assignmentupgrade'));
-            }
-
-
-        }
-
-        $output .= $this->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
-
-
-        $output .= $this->footer();
-        return $output;
-    }
-
     /**
      * Render the result of an assignment conversion
      * @param stdClass $assignmentsummary data about the assignment to upgrade.
@@ -186,19 +154,18 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
      */
     public function convert_assignment_result($assignmentsummary, $success, $log) {
         $output = '';
-        $output .= $this->header();
-        $output .= $this->heading(get_string('conversioncomplete', 'tool_assignmentupgrade'));
 
+        $output .= $this->container_start('tool_assignmentupgrade_result');
+        $output .= $this->container(get_string('upgradeassignmentsummary', 'tool_assignmentupgrade', $assignmentsummary));
         if (!$success) {
-            $output .= get_string('conversionfailed', 'tool_assignmentupgrade', $log);
+            $output .= $this->container(get_string('conversionfailed', 'tool_assignmentupgrade', $log));
         } else {
-            $output .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$assignmentsummary->courseid)) ,get_string('viewcourse', 'tool_assignmentupgrade'));
+            $output .= $this->container(get_string('upgradeassignmentsuccess', 'tool_assignmentupgrade'));
+            
+            $output .= $this->container(html_writer::link(new moodle_url('/course/view.php', array('id'=>$assignmentsummary->courseid)) ,get_string('viewcourse', 'tool_assignmentupgrade')));
         }
+        $output .= $this->container_end();
 
-        $output .= $this->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
-
-
-        $output .= $this->footer();
         return $output;
     }
 
index 0188dc4..277400b 100644 (file)
@@ -8,4 +8,4 @@
 #page-admin-tool-assignmentupgrade-listnotupgraded .tool_assignmentupgrade_upgradetable tr.selectedrow td { background-color: #ffeecc; }
 #page-admin-tool-assignmentupgrade-listnotupgraded .tool_assignmentupgrade_upgradetable tr.unselectedrow td { background-color: white; }
 
-
+#page-admin-tool-assignmentupgrade-listnotupgraded .tool_assignmentupgrade_paginationform .hidden { display: none; }
index 0e4830b..307a8c9 100644 (file)
@@ -70,12 +70,11 @@ class tool_assignmentupgrade_assignments_table extends table_sql implements rend
         $from = '{assignment} a JOIN {course} c ON a.course = c.id ' .
                         ' LEFT JOIN {assignment_submissions} s ON a.id = s.assignment';
 
-
         $where = '1 = 1';
         $where .= ' GROUP BY a.id, a.name, a.assignmenttype, c.shortname, c.id ';
 
         $this->set_sql($fields, $from, $where, array());
-        $this->set_count_sql('SELECT COUNT(*) FROM ' . $from, array());
+        $this->set_count_sql('SELECT COUNT(*) FROM {assignment} a JOIN {course} c ON a.course = c.id', array());
 
         $columns = array();
         $headers = array();
index 2464ebe..5125bbb 100644 (file)
@@ -23,8 +23,8 @@
  */
 
 require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
 require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
 
 require_sesskey();
 
@@ -36,13 +36,11 @@ admin_externalpage_setup('assignmentupgrade', '', array(), tool_assignmentupgrad
 $PAGE->navbar->add(get_string('upgradesingle', 'tool_assignmentupgrade'));
 $renderer = $PAGE->get_renderer('tool_assignmentupgrade');
 
-$assignmentinfo = tool_assignmentupgrade_get_assignment($assignmentid);
-if (!$assignmentinfo) {
-    print_error('invalidrequest');
-    die();
-}
-
 $log = '';
-$result = tool_assignmentupgrade_upgrade_assignment($assignmentinfo, $log);
+list($summary, $success, $log) = tool_assignmentupgrade_upgrade_assignment($assignmentid);
 
-echo $renderer->convert_assignment_result($assignmentinfo, $result, $log);
+echo $renderer->header();
+echo $renderer->heading(get_string('conversioncomplete', 'tool_assignmentupgrade'));
+echo $renderer->convert_assignment_result($summary, $success, $log);
+echo $renderer->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
+echo $renderer->footer();
index 0325b4a..b7ec24c 100644 (file)
@@ -23,8 +23,8 @@
  */
 
 require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
 require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
 
 require_sesskey();
 
index d17dc66..cb9a767 100644 (file)
@@ -29,6 +29,12 @@ require_once($CFG->dirroot.'/mod/assign/locallib.php');
 /** Include accesslib.php */
 require_once($CFG->libdir.'/accesslib.php');
 
+/**
+ * The maximum amount of time to spend upgrading a single assignment.
+ * This is intentionally generous (5 mins) as the effect of a timeout
+ * for a legitimate upgrade would be quite harsh (roll back code will not run)
+ */
+define('ASSIGN_MAX_UPGRADE_TIME_SECS', 300);
 
 /**
  * Class to manage upgrades from mod_assignment to mod_assign
@@ -48,9 +54,7 @@ class assign_upgrade_manager {
      * @return bool true or false
      */
     public function upgrade_assignment($oldassignmentid, & $log) {
-        global $DB, $CFG;
         // steps to upgrade an assignment
-
         global $DB, $CFG, $USER;
         // steps to upgrade an assignment
 
@@ -59,6 +63,9 @@ class assign_upgrade_manager {
               return false;
         }
 
+        // should we use a shutdown handler to rollback on timeout?
+        @set_time_limit(ASSIGN_MAX_UPGRADE_TIME_SECS);
+
 
         // get the module details
         $oldmodule = $DB->get_record('modules', array('name'=>'assignment'), '*', MUST_EXIST);
@@ -217,7 +224,7 @@ class assign_upgrade_manager {
 
         } catch (Exception $exception) {
             $rollback = true;
-            $log .= get_string('conversionexception', 'mod_assign', $exception->getMessage());
+            $log .= get_string('conversionexception', 'mod_assign', $exception->error);
         }
 
         if ($rollback) {