/**
  * @return object the data to construct a question like
  * {@link qtype_gapselect_test_helper::make_a_gapselect_question()}.
  */
 protected function get_test_question_data()
 {
     global $USER;
     $gapselect = new stdClass();
     $gapselect->id = 0;
     $gapselect->category = 0;
     $gapselect->contextid = 0;
     $gapselect->parent = 0;
     $gapselect->questiontextformat = FORMAT_HTML;
     $gapselect->generalfeedbackformat = FORMAT_HTML;
     $gapselect->defaultmark = 1;
     $gapselect->penalty = 0.3333333;
     $gapselect->length = 1;
     $gapselect->stamp = make_unique_id_code();
     $gapselect->version = make_unique_id_code();
     $gapselect->hidden = 0;
     $gapselect->timecreated = time();
     $gapselect->timemodified = time();
     $gapselect->createdby = $USER->id;
     $gapselect->modifiedby = $USER->id;
     $gapselect->name = 'Selection from drop down list question';
     $gapselect->questiontext = 'The [[1]] brown [[2]] jumped over the [[3]] dog.';
     $gapselect->generalfeedback = 'This sentence uses each letter of the alphabet.';
     $gapselect->qtype = 'gapselect';
     $gapselect->options = new stdClass();
     $gapselect->options->shuffleanswers = true;
     test_question_maker::set_standard_combined_feedback_fields($gapselect->options);
     $gapselect->options->answers = array((object) array('answer' => 'quick', 'feedback' => '1'), (object) array('answer' => 'fox', 'feedback' => '2'), (object) array('answer' => 'lazy', 'feedback' => '3'), (object) array('answer' => 'assiduous', 'feedback' => '3'), (object) array('answer' => 'dog', 'feedback' => '2'), (object) array('answer' => 'slow', 'feedback' => '1'));
     return $gapselect;
 }
Example #2
0
 protected function get_unknown_questiondata()
 {
     $questiondata = new stdClass();
     $questiondata->id = 0;
     $questiondata->category = 0;
     $questiondata->contextid = 0;
     $questiondata->parent = 0;
     $questiondata->name = 'Test';
     $questiondata->questiontext = 'This is the question text.';
     $questiondata->questiontextformat = FORMAT_HTML;
     $questiondata->generalfeedback = 'This is the general feedback.';
     $questiondata->generalfeedbackformat = FORMAT_HTML;
     $questiondata->defaultmark = 1;
     $questiondata->penalty = 0.3333333;
     $questiondata->qtype = 'strange_unknown';
     $questiondata->length = 1;
     $questiondata->stamp = make_unique_id_code();
     $questiondata->version = make_unique_id_code();
     $questiondata->hidden = 0;
     $questiondata->timecreated = 0;
     $questiondata->timemodified = 0;
     $questiondata->createdby = 0;
     $questiondata->modifiedby = 0;
     return $questiondata;
 }
 /**
  * Get the question data, as it would be loaded by get_question_options.
  * @return object
  */
 public static function get_linkerdesc_question_data_info()
 {
     global $USER;
     $qdata = new stdClass();
     $qdata->id = 0;
     $qdata->contextid = 0;
     $qdata->category = 0;
     $qdata->parent = 0;
     $qdata->stamp = make_unique_id_code();
     $qdata->version = make_unique_id_code();
     $qdata->timecreated = time();
     $qdata->timemodified = time();
     $qdata->createdby = $USER->id;
     $qdata->modifiedby = $USER->id;
     $qdata->qtype = 'linkerdesc';
     $qdata->name = 'Description';
     $qdata->questiontext = 'Here is some information about the questions you are about to attempt.';
     $qdata->questiontextformat = FORMAT_HTML;
     $qdata->generalfeedback = 'And here is some more text shown only on the review page.';
     $qdata->generalfeedbackformat = FORMAT_HTML;
     $qdata->defaultmark = 0;
     $qdata->length = 0;
     $qdata->penalty = 0;
     $qdata->hidden = 0;
     $qdata->hints = array();
     $qdata->options = new stdClass();
     $qdata->options->answers = array();
     return $qdata;
 }
 /**
  * @return object the data to construct a question like
  * {@link qtype_ddwtos_test_helper::make_ddwtos_question_fox()}.
  */
 protected function get_test_question_data()
 {
     global $USER;
     $dd = new stdClass();
     $dd->id = 0;
     $dd->category = 0;
     $dd->contextid = 0;
     $dd->parent = 0;
     $dd->questiontextformat = FORMAT_HTML;
     $dd->generalfeedbackformat = FORMAT_HTML;
     $dd->defaultmark = 1;
     $dd->penalty = 0.3333333;
     $dd->length = 1;
     $dd->stamp = make_unique_id_code();
     $dd->version = make_unique_id_code();
     $dd->hidden = 0;
     $dd->timecreated = time();
     $dd->timemodified = time();
     $dd->createdby = $USER->id;
     $dd->modifiedby = $USER->id;
     $dd->name = 'Drag-and-drop words into sentences question';
     $dd->questiontext = 'The [[1]] brown [[2]] jumped over the [[3]] dog.';
     $dd->generalfeedback = 'This sentence uses each letter of the alphabet.';
     $dd->qtype = 'ddwtos';
     $dd->options = new stdClass();
     $dd->options->shuffleanswers = true;
     test_question_maker::set_standard_combined_feedback_fields($dd->options);
     $dd->options->answers = array((object) array('answer' => 'quick', 'feedback' => 'O:8:"stdClass":2:{s:9:"draggroup";s:1:"1";s:8:"infinite";i:0;}'), (object) array('answer' => 'fox', 'feedback' => 'O:8:"stdClass":2:{s:9:"draggroup";s:1:"2";s:8:"infinite";i:0;}'), (object) array('answer' => 'lazy', 'feedback' => 'O:8:"stdClass":2:{s:9:"draggroup";s:1:"3";s:8:"infinite";i:0;}'), (object) array('answer' => 'assiduous', 'feedback' => 'O:8:"stdClass":2:{s:9:"draggroup";s:1:"3";s:8:"infinite";i:0;}'), (object) array('answer' => 'dog', 'feedback' => 'O:8:"stdClass":2:{s:9:"draggroup";s:1:"2";s:8:"infinite";i:0;}'), (object) array('answer' => 'slow', 'feedback' => 'O:8:"stdClass":2:{s:9:"draggroup";s:1:"1";s:8:"infinite";i:0;}'));
     return $dd;
 }
 protected function get_test_question_data()
 {
     global $USER;
     $q = new stdClass();
     $q->id = 0;
     $q->name = 'Gapfill Question';
     $q->category = 0;
     $q->contextid = 0;
     $q->parent = 0;
     $q->questiontext = 'The [cat] sat on the [mat]';
     $q->questiontextformat = FORMAT_HTML;
     $q->generalfeedback = 'General feedback.';
     $q->generalfeedbackformat = FORMAT_HTML;
     $q->defaultmark = 1;
     $q->penalty = 0.3333333;
     $q->length = 1;
     $q->stamp = make_unique_id_code();
     $q->version = make_unique_id_code();
     $q->hidden = 0;
     $q->timecreated = time();
     $q->timemodified = time();
     $q->createdby = $USER->id;
     $q->modifiedby = $USER->id;
     $q->options = new stdClass();
     test_question_maker::set_standard_combined_feedback_fields($q->options);
     $q->options->displayanswers = 0;
     $q->options->delimitchars = "[]";
     return $q;
 }
 protected function get_test_question_data()
 {
     global $USER;
     $q = new stdClass();
     $q->id = 0;
     $q->name = 'Drag and drop matching question';
     $q->category = 0;
     $q->contextid = 0;
     $q->parent = 0;
     $q->questiontext = 'Classify the animals.';
     $q->questiontextformat = FORMAT_HTML;
     $q->generalfeedback = 'General feedback.';
     $q->generalfeedbackformat = FORMAT_HTML;
     $q->defaultmark = 1;
     $q->penalty = 0.3333333;
     $q->length = 1;
     $q->stamp = make_unique_id_code();
     $q->version = make_unique_id_code();
     $q->hidden = 0;
     $q->timecreated = time();
     $q->timemodified = time();
     $q->createdby = $USER->id;
     $q->modifiedby = $USER->id;
     $q->options = new stdClass();
     $q->options->shuffleanswers = false;
     test_question_maker::set_standard_combined_feedback_fields($q->options);
     $q->options->subquestions = array(14 => (object) array('id' => 14, 'questiontext' => 'frog', 'questiontextformat' => FORMAT_HTML, 'answertext' => 'amphibian', 'answertextformat' => FORMAT_HTML), 15 => (object) array('id' => 15, 'questiontext' => 'cat', 'questiontextformat' => FORMAT_HTML, 'answertext' => 'mammal', 'answertextformat' => FORMAT_HTML), 16 => (object) array('id' => 16, 'questiontext' => 'newt', 'questiontextformat' => FORMAT_HTML, 'answertext' => 'amphibian', 'answertextformat' => FORMAT_HTML), 17 => (object) array('id' => 17, 'questiontext' => '', 'questiontextformat' => FORMAT_HTML, 'answertext' => 'insect', 'answertextformat' => FORMAT_HTML));
     return $q;
 }
Example #7
0
 /**
  * Create a new question category.
  * @param array|stdClass $record
  * @return stdClass question_categories record.
  */
 public function create_question_category($record = null)
 {
     global $DB;
     $this->categorycount++;
     $defaults = array('name' => 'Test question category ' . $this->categorycount, 'contextid' => context_system::instance()->id, 'info' => '', 'infoformat' => FORMAT_HTML, 'stamp' => make_unique_id_code(), 'parent' => 0, 'sortorder' => 999);
     $record = $this->datagenerator->combine_defaults_and_record($defaults, $record);
     $record['id'] = $DB->insert_record('question_categories', $record);
     return (object) $record;
 }
Example #8
0
    protected function get_test_question_data() {
        global $USER;
        $q = new stdClass();
        $q->id = 0;
        $q->name = 'Simple multianswer';
        $q->category = 0;
        $q->contextid = 0;
        $q->parent = 0;
        $q->questiontext =
                'Complete this opening line of verse: "The {#1} and the {#2} went to sea".';
        $q->questiontextformat = FORMAT_HTML;
        $q->generalfeedback = 'Generalfeedback: It\'s from "The Owl and the Pussy-cat" by Lear: ' .
                '"The owl and the pussycat went to see';
        $q->generalfeedbackformat = FORMAT_HTML;
        $q->defaultmark = 2;
        $q->penalty = 0.3333333;
        $q->length = 1;
        $q->stamp = make_unique_id_code();
        $q->version = make_unique_id_code();
        $q->hidden = 0;
        $q->timecreated = time();
        $q->timemodified = time();
        $q->createdby = $USER->id;
        $q->modifiedby = $USER->id;

        $sadata = new stdClass();
        $sadata->id = 1;
        $sadata->qtype = 'shortanswer';
        $sadata->defaultmark = 1;
        $sadata->options->usecase = true;
        $sadata->options->answers[1] = (object) array('answer' => 'Bow-wow', 'fraction' => 0);
        $sadata->options->answers[2] = (object) array('answer' => 'Wiggly worm', 'fraction' => 0);
        $sadata->options->answers[3] = (object) array('answer' => 'Pussy-cat', 'fraction' => 1);

        $mcdata = new stdClass();
        $mcdata->id = 1;
        $mcdata->qtype = 'multichoice';
        $mcdata->defaultmark = 1;
        $mcdata->options->single = true;
        $mcdata->options->answers[1] = (object) array('answer' => 'Dog', 'fraction' => 0);
        $mcdata->options->answers[2] = (object) array('answer' => 'Owl', 'fraction' => 1);
        $mcdata->options->answers[3] = (object) array('answer' => '*', 'fraction' => 0);

        $q->options->questions = array(
            1 => $sadata,
            2 => $mcdata,
        );

        return $q;
    }
Example #9
0
 public function make_test_question() {
     global $USER;
     $q = new stdClass();
     $q->id = 0;
     $q->contextid = 0;
     $q->category = 0;
     $q->parent = 0;
     $q->questiontextformat = FORMAT_HTML;
     $q->generalfeedbackformat = FORMAT_HTML;
     $q->defaultmark = 1;
     $q->penalty = 0.3333333;
     $q->length = 1;
     $q->stamp = make_unique_id_code();
     $q->version = make_unique_id_code();
     $q->hidden = 0;
     $q->timecreated = time();
     $q->timemodified = time();
     $q->createdby = $USER->id;
     $q->modifiedby = $USER->id;
     return $q;
 }
Example #10
0
/**
* Gets the default category in a course
*
* It returns the first category with no parent category. If no categories
* exist yet then one is created.
* @return object The default category
* @param integer $courseid  The id of the course whose default category is wanted
*/
function get_default_question_category($courseid)
{
    // If it already exists, just return it.
    if ($category = get_records_select("question_categories", "course = '{$courseid}' AND parent = '0'", 'id', '*', '', 1)) {
        return reset($category);
    }
    // Otherwise, we need to make one
    $category = new stdClass();
    $category->name = get_string("default", "quiz");
    $category->info = get_string("defaultinfo", "quiz");
    $category->course = $courseid;
    $category->parent = 0;
    $category->sortorder = 999;
    // By default, all categories get this number, and are sorted alphabetically.
    $category->publish = 0;
    $category->stamp = make_unique_id_code();
    if (!($category->id = insert_record("question_categories", $category))) {
        notify("Error creating a default category!");
        return false;
    }
    return $category;
}
Example #11
0
/**
* Gets the default category in the most specific context.
* If no categories exist yet then default ones are created in all contexts.
*
* @param array $contexts  The context objects for this context and all parent contexts.
* @return object The default category - the category in the course context
*/
function question_make_default_categories($contexts)
{
    $toreturn = null;
    // If it already exists, just return it.
    foreach ($contexts as $key => $context) {
        if (!($categoryrs = get_recordset_select("question_categories", "contextid = '{$context->id}'", 'sortorder, name', '*', '', 1))) {
            error('error getting category record');
        } else {
            if (!($category = rs_fetch_record($categoryrs))) {
                // Otherwise, we need to make one
                $category = new stdClass();
                $contextname = print_context_name($context, false, true);
                $category->name = addslashes(get_string('defaultfor', 'question', $contextname));
                $category->info = addslashes(get_string('defaultinfofor', 'question', $contextname));
                $category->contextid = $context->id;
                $category->parent = 0;
                $category->sortorder = 999;
                // By default, all categories get this number, and are sorted alphabetically.
                $category->stamp = make_unique_id_code();
                if (!($category->id = insert_record('question_categories', $category))) {
                    error('Error creating a default category for context ' . print_context_name($context));
                }
            }
        }
        if ($context->contextlevel == CONTEXT_COURSE) {
            $toreturn = clone $category;
        }
    }
    return $toreturn;
}
function addRandomQuizQuestions($cmid, $cat_id)
{
    global $QTYPES;
    $result = true;
    $recurse = 1;
    list($quiz, $cm) = get_module_from_cmid($cmid);
    if ($rs = get_records('question_categories', 'parent', $cat_id, 'sortorder')) {
        $course = get_record('course', 'id', $quiz->course);
        foreach ($rs as $cat) {
            $categoryid = $cat->id;
            $randomcount = 1;
            // load category
            if (!($category = get_record('question_categories', 'id', $categoryid))) {
                error('Category ID is incorrect');
            }
            $catcontext = get_context_instance_by_id($category->contextid);
            require_capability('moodle/question:useall', $catcontext);
            $category->name = addslashes($category->name);
            // Find existing random questions in this category that are not used by any quiz.
            if ($existingquestions = get_records_sql("SELECT * FROM " . $CFG->prefix . "question q\n                        WHERE qtype = '" . RANDOM . "'\n                            AND category = {$category->id}\n                            AND " . sql_compare_text('questiontext') . " = '{$recurse}'\n                            AND NOT EXISTS (SELECT * FROM " . $CFG->prefix . "quiz_question_instances WHERE question = q.id)\n                        ORDER BY id")) {
                // Take as many of these as needed.
                while ($existingquestion = array_shift($existingquestions) and $randomcount > 0) {
                    if (!quiz_add_quiz_question($existingquestion->id, $quiz)) {
                        $result = false;
                    }
                    $randomcount--;
                }
            }
            // If more are needed, create them.
            if ($randomcount > 0) {
                //echo "NOT EXISTING:".$cat->id."<br/>";
                $form->questiontext = $recurse;
                // we use the questiontext field to store the info
                // on whether to include questions in subcategories
                $form->questiontextformat = 0;
                $form->image = '';
                $form->defaultgrade = 1;
                $form->hidden = 1;
                for ($i = 0; $i < $randomcount; $i++) {
                    $form->category = "{$category->id},{$category->contextid}";
                    $form->stamp = make_unique_id_code();
                    // Set the unique code (not to be changed)
                    $question = new stdClass();
                    $question->qtype = RANDOM;
                    $question = $QTYPES[RANDOM]->save_question($question, $form, $course);
                    if (!isset($question->id)) {
                        error('Could not insert new random question!');
                        $result = false;
                    }
                    //quiz_add_quiz_question($question->id, $quiz);
                    if (!quiz_add_quiz_question($question->id, $quiz)) {
                        $result = false;
                    }
                }
            }
            $significantchangemade = true;
        }
    }
    return $result;
    /*
        $result = true;
        $recurse = 1;
       list($quiz, $cm) = get_module_from_cmid($cmid);
       if ($rs = get_recordset('question_categories','parent',$cat_id)) {
               $course = get_record('course','id',$quiz->course);
                foreach ($rs as $category) {
                        echo $category->name."<br/>";
                        /// Add random questions to the quiz
                        // - Source from: /mod/quiz/edit.php
                        $randomcount = 1;
                        // load category
                       //$catcontext = get_context_instance_by_id($category->contextid);
                        //require_capability('moodle/question:useall', $catcontext);
                        $category->name = $category->name;
                        // Find existing random questions in this category that are
                        // not used by any quiz.
                        if ($existingquestions = get_records_sql(
                                "SELECT q.id,q.qtype FROM {question} q
                                WHERE qtype = '" . RANDOM . "'
                                    AND category = ?
                                    AND " . $DB->sql_compare_text('questiontext') . " = ?
                                    AND NOT EXISTS (SELECT * FROM {quiz_question_instances} WHERE question = q.id)
                                ORDER BY id", array($category->id, $recurse))) {
                            // Take as many of these as needed.
                            while (($existingquestion = array_shift($existingquestions)) && $randomcount > 0) {
                                //quiz_add_quiz_question($existingquestion->id, $quiz);
                                if(!quiz_add_quiz_question($existingquestion->id, $quiz)){
                                    $result = false;
                                }
                                $randomcount--;
                            }
                        }
                       // If more are needed, create them.
                        if ($randomcount > 0) {
                           $form->questiontext = $recurse; // we use the questiontext field
                                    // to store the info on whether to include
                                    // questions in subcategories
                            $form->questiontextformat = 0;
                            $form->image = '';
                            $form->defaultgrade = 1;
                            $form->hidden = 1;
                            for ($i = 0; $i < $randomcount; $i++) {
                                $form->category = $category->id . ',' . $category->contextid;
                                $form->stamp = make_unique_id_code(); // Set the unique
                                        //code (not to be changed)
                                $question = new stdClass;
                                $question->qtype = RANDOM;
                                $question = $QTYPES[RANDOM]->save_question($question, $form, $course);
                               if(!isset($question->id)) {
                                    //print_error('cannotinsertrandomquestion', 'quiz');
                                    $result = false;
                                }
                                //quiz_add_quiz_question($question->id, $quiz);
                                if(!quiz_add_quiz_question($question->id, $quiz)){
                                    $result = false;
                                }
                            }
                        }
                       quiz_update_sumgrades($quiz);
                        quiz_delete_previews($quiz);
               }
                //$rs->close(); /// Don't forget to close the recordset!
        }
        return $result;
    */
}
/**
 * Gets the default category in the most specific context.
 * If no categories exist yet then default ones are created in all contexts.
 *
 * @param array $contexts  The context objects for this context and all parent contexts.
 * @return object The default category - the category in the course context
 */
function question_make_default_categories($contexts)
{
    global $DB;
    static $preferredlevels = array(CONTEXT_COURSE => 4, CONTEXT_MODULE => 3, CONTEXT_COURSECAT => 2, CONTEXT_SYSTEM => 1);
    $toreturn = null;
    $preferredness = 0;
    // If it already exists, just return it.
    foreach ($contexts as $key => $context) {
        if (!($exists = $DB->record_exists("question_categories", array('contextid' => $context->id)))) {
            // Otherwise, we need to make one
            $category = new stdClass();
            $contextname = $context->get_context_name(false, true);
            $category->name = get_string('defaultfor', 'question', $contextname);
            $category->info = get_string('defaultinfofor', 'question', $contextname);
            $category->contextid = $context->id;
            $category->parent = 0;
            // By default, all categories get this number, and are sorted alphabetically.
            $category->sortorder = 999;
            $category->stamp = make_unique_id_code();
            $category->id = $DB->insert_record('question_categories', $category);
        } else {
            $category = question_get_default_category($context->id);
        }
        $thispreferredness = $preferredlevels[$context->contextlevel];
        if (has_any_capability(array('moodle/question:usemine', 'moodle/question:useall'), $context)) {
            $thispreferredness += 10;
        }
        if ($thispreferredness > $preferredness) {
            $toreturn = $category;
            $preferredness = $thispreferredness;
        }
    }
    if (!is_null($toreturn)) {
        $toreturn = clone $toreturn;
    }
    return $toreturn;
}
Example #14
0
 public static function initialise_question_data($qdata)
 {
     global $USER;
     $qdata->id = 0;
     $qdata->category = 0;
     $qdata->contextid = 0;
     $qdata->parent = 0;
     $qdata->questiontextformat = FORMAT_HTML;
     $qdata->generalfeedbackformat = FORMAT_HTML;
     $qdata->defaultmark = 1;
     $qdata->penalty = 0.3333333;
     $qdata->length = 1;
     $qdata->stamp = make_unique_id_code();
     $qdata->version = make_unique_id_code();
     $qdata->hidden = 0;
     $qdata->timecreated = time();
     $qdata->timemodified = time();
     $qdata->createdby = $USER->id;
     $qdata->modifiedby = $USER->id;
     $qdata->hints = array();
 }
Example #15
0
/**
 * Main upgrade tasks to be executed on Moodle version bump
 *
 * This function is automatically executed after one bump in the Moodle core
 * version is detected. It's in charge of performing the required tasks
 * to raise core from the previous version to the next one.
 *
 * It's a collection of ordered blocks of code, named "upgrade steps",
 * each one performing one isolated (from the rest of steps) task. Usually
 * tasks involve creating new DB objects or performing manipulation of the
 * information for cleanup/fixup purposes.
 *
 * Each upgrade step has a fixed structure, that can be summarised as follows:
 *
 * if ($oldversion < XXXXXXXXXX.XX) {
 *     // Explanation of the update step, linking to issue in the Tracker if necessary
 *     upgrade_set_timeout(XX); // Optional for big tasks
 *     // Code to execute goes here, usually the XMLDB Editor will
 *     // help you here. See {@link http://docs.moodle.org/dev/XMLDB_editor}.
 *     upgrade_main_savepoint(true, XXXXXXXXXX.XX);
 * }
 *
 * All plugins within Moodle (modules, blocks, reports...) support the existence of
 * their own upgrade.php file, using the "Frankenstyle" component name as
 * defined at {@link http://docs.moodle.org/dev/Frankenstyle}, for example:
 *     - {@link xmldb_page_upgrade($oldversion)}. (modules don't require the plugintype ("mod_") to be used.
 *     - {@link xmldb_auth_manual_upgrade($oldversion)}.
 *     - {@link xmldb_workshopform_accumulative_upgrade($oldversion)}.
 *     - ....
 *
 * In order to keep the contents of this file reduced, it's allowed to create some helper
 * functions to be used here in the {@link upgradelib.php} file at the same directory. Note
 * that such a file must be manually included from upgrade.php, and there are some restrictions
 * about what can be used within it.
 *
 * For more information, take a look to the documentation available:
 *     - Data definition API: {@link http://docs.moodle.org/dev/Data_definition_API}
 *     - Upgrade API: {@link http://docs.moodle.org/dev/Upgrade_API}
 *
 * @param int $oldversion
 * @return bool always true
 */
function xmldb_main_upgrade($oldversion)
{
    global $CFG, $DB;
    require_once $CFG->libdir . '/db/upgradelib.php';
    // Core Upgrade-related functions.
    $dbman = $DB->get_manager();
    // Loads ddl manager and xmldb classes.
    // Always keep this upgrade step with version being the minimum
    // allowed version to upgrade from (v2.7.0 right now).
    if ($oldversion < 2014051200) {
        // Just in case somebody hacks upgrade scripts or env, we really can not continue.
        echo "You need to upgrade to 2.7.x or higher first!\n";
        exit(1);
        // Note this savepoint is 100% unreachable, but needed to pass the upgrade checks.
        upgrade_main_savepoint(true, 2014051200);
    }
    // MDL-32543 Make sure that the log table has correct length for action and url fields.
    if ($oldversion < 2014051200.02) {
        $table = new xmldb_table('log');
        $columns = $DB->get_columns('log');
        if ($columns['action']->max_length < 40) {
            $index1 = new xmldb_index('course-module-action', XMLDB_INDEX_NOTUNIQUE, array('course', 'module', 'action'));
            if ($dbman->index_exists($table, $index1)) {
                $dbman->drop_index($table, $index1);
            }
            $index2 = new xmldb_index('action', XMLDB_INDEX_NOTUNIQUE, array('action'));
            if ($dbman->index_exists($table, $index2)) {
                $dbman->drop_index($table, $index2);
            }
            $field = new xmldb_field('action', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null, 'cmid');
            $dbman->change_field_precision($table, $field);
            $dbman->add_index($table, $index1);
            $dbman->add_index($table, $index2);
        }
        if ($columns['url']->max_length < 100) {
            $field = new xmldb_field('url', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'action');
            $dbman->change_field_precision($table, $field);
        }
        upgrade_main_savepoint(true, 2014051200.02);
    }
    if ($oldversion < 2014060300.0) {
        $gspath = get_config('assignfeedback_editpdf', 'gspath');
        if ($gspath !== false) {
            set_config('pathtogs', $gspath);
            unset_config('gspath', 'assignfeedback_editpdf');
        }
        upgrade_main_savepoint(true, 2014060300.0);
    }
    if ($oldversion < 2014061000.0) {
        // Fixing possible wrong MIME type for Publisher files.
        $filetypes = array('%.pub' => 'application/x-mspublisher');
        upgrade_mimetypes($filetypes);
        upgrade_main_savepoint(true, 2014061000.0);
    }
    if ($oldversion < 2014062600.01) {
        // We only want to delete DragMath if the directory no longer exists. If the directory
        // is present then it means it has been restored, so do not perform the uninstall.
        if (!check_dir_exists($CFG->libdir . '/editor/tinymce/plugins/dragmath', false)) {
            // Purge DragMath plugin which is incompatible with GNU GPL license.
            unset_all_config_for_plugin('tinymce_dragmath');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014062600.01);
    }
    // Switch the order of the fields in the files_reference index, to improve the performance of search_references.
    if ($oldversion < 2014070100.0) {
        $table = new xmldb_table('files_reference');
        $index = new xmldb_index('uq_external_file', XMLDB_INDEX_UNIQUE, array('repositoryid', 'referencehash'));
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        upgrade_main_savepoint(true, 2014070100.0);
    }
    if ($oldversion < 2014070101.0) {
        $table = new xmldb_table('files_reference');
        $index = new xmldb_index('uq_external_file', XMLDB_INDEX_UNIQUE, array('referencehash', 'repositoryid'));
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        upgrade_main_savepoint(true, 2014070101.0);
    }
    if ($oldversion < 2014072400.01) {
        $table = new xmldb_table('user_devices');
        $oldindex = new xmldb_index('pushid-platform', XMLDB_KEY_UNIQUE, array('pushid', 'platform'));
        if ($dbman->index_exists($table, $oldindex)) {
            $key = new xmldb_key('pushid-platform', XMLDB_KEY_UNIQUE, array('pushid', 'platform'));
            $dbman->drop_key($table, $key);
        }
        upgrade_main_savepoint(true, 2014072400.01);
    }
    if ($oldversion < 2014080801.0) {
        // Define index behaviour (not unique) to be added to question_attempts.
        $table = new xmldb_table('question_attempts');
        $index = new xmldb_index('behaviour', XMLDB_INDEX_NOTUNIQUE, array('behaviour'));
        // Conditionally launch add index behaviour.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014080801.0);
    }
    if ($oldversion < 2014082900.01) {
        // Fixing possible wrong MIME type for 7-zip and Rar files.
        $filetypes = array('%.7z' => 'application/x-7z-compressed', '%.rar' => 'application/x-rar-compressed');
        upgrade_mimetypes($filetypes);
        upgrade_main_savepoint(true, 2014082900.01);
    }
    if ($oldversion < 2014082900.02) {
        // Replace groupmembersonly usage with new availability system.
        $transaction = $DB->start_delegated_transaction();
        if ($CFG->enablegroupmembersonly) {
            // If it isn't already enabled, we need to enable availability.
            if (!$CFG->enableavailability) {
                set_config('enableavailability', 1);
            }
            // Count all course-modules with groupmembersonly set (for progress
            // bar).
            $total = $DB->count_records('course_modules', array('groupmembersonly' => 1));
            $pbar = new progress_bar('upgradegroupmembersonly', 500, true);
            // Get all these course-modules, one at a time.
            $rs = $DB->get_recordset('course_modules', array('groupmembersonly' => 1), 'course, id');
            $i = 0;
            foreach ($rs as $cm) {
                // Calculate and set new availability value.
                $availability = upgrade_group_members_only($cm->groupingid, $cm->availability);
                $DB->set_field('course_modules', 'availability', $availability, array('id' => $cm->id));
                // Update progress.
                $i++;
                $pbar->update($i, $total, "Upgrading groupmembersonly settings - {$i}/{$total}.");
            }
            $rs->close();
        }
        // Define field groupmembersonly to be dropped from course_modules.
        $table = new xmldb_table('course_modules');
        $field = new xmldb_field('groupmembersonly');
        // Conditionally launch drop field groupmembersonly.
        if ($dbman->field_exists($table, $field)) {
            $dbman->drop_field($table, $field);
        }
        // Unset old config variable.
        unset_config('enablegroupmembersonly');
        $transaction->allow_commit();
        upgrade_main_savepoint(true, 2014082900.02);
    }
    if ($oldversion < 2014100100.0) {
        // Define table messageinbound_handlers to be created.
        $table = new xmldb_table('messageinbound_handlers');
        // Adding fields to table messageinbound_handlers.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('classname', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('defaultexpiration', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '86400');
        $table->add_field('validateaddress', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1');
        $table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
        // Adding keys to table messageinbound_handlers.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('classname', XMLDB_KEY_UNIQUE, array('classname'));
        // Conditionally launch create table for messageinbound_handlers.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Define table messageinbound_datakeys to be created.
        $table = new xmldb_table('messageinbound_datakeys');
        // Adding fields to table messageinbound_datakeys.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('handler', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('datavalue', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('datakey', XMLDB_TYPE_CHAR, '64', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('expires', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        // Adding keys to table messageinbound_datakeys.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('handler_datavalue', XMLDB_KEY_UNIQUE, array('handler', 'datavalue'));
        $table->add_key('handler', XMLDB_KEY_FOREIGN, array('handler'), 'messageinbound_handlers', array('id'));
        // Conditionally launch create table for messageinbound_datakeys.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100100.0);
    }
    if ($oldversion < 2014100600.01) {
        // Define field aggregationstatus to be added to grade_grades.
        $table = new xmldb_table('grade_grades');
        $field = new xmldb_field('aggregationstatus', XMLDB_TYPE_CHAR, '10', null, XMLDB_NOTNULL, null, 'unknown', 'timemodified');
        // Conditionally launch add field aggregationstatus.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('aggregationweight', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null, 'aggregationstatus');
        // Conditionally launch add field aggregationweight.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field aggregationcoef2 to be added to grade_items.
        $table = new xmldb_table('grade_items');
        $field = new xmldb_field('aggregationcoef2', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, '0', 'aggregationcoef');
        // Conditionally launch add field aggregationcoef2.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('weightoverride', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'needsupdate');
        // Conditionally launch add field weightoverride.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.01);
    }
    if ($oldversion < 2014100600.02) {
        // Define field aggregationcoef2 to be added to grade_items_history.
        $table = new xmldb_table('grade_items_history');
        $field = new xmldb_field('aggregationcoef2', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, '0', 'aggregationcoef');
        // Conditionally launch add field aggregationcoef2.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.02);
    }
    if ($oldversion < 2014100600.03) {
        // Define field weightoverride to be added to grade_items_history.
        $table = new xmldb_table('grade_items_history');
        $field = new xmldb_field('weightoverride', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'decimals');
        // Conditionally launch add field weightoverride.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.03);
    }
    if ($oldversion < 2014100600.04) {
        // Set flags so we can display a notice on all courses that might
        // be affected by the uprade to natural aggregation.
        if (!get_config('grades_sumofgrades_upgrade_flagged', 'core')) {
            // 13 == SUM_OF_GRADES.
            $sql = 'SELECT DISTINCT courseid
                      FROM {grade_categories}
                     WHERE aggregation = ?';
            $courses = $DB->get_records_sql($sql, array(13));
            foreach ($courses as $course) {
                set_config('show_sumofgrades_upgrade_' . $course->courseid, 1);
                // Set each of the grade items to needing an update so that when the user visits the grade reports the
                // figures will be updated.
                $DB->set_field('grade_items', 'needsupdate', 1, array('courseid' => $course->courseid));
            }
            set_config('grades_sumofgrades_upgrade_flagged', 1);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100600.04);
    }
    if ($oldversion < 2014100700.0) {
        // Define table messageinbound_messagelist to be created.
        $table = new xmldb_table('messageinbound_messagelist');
        // Adding fields to table messageinbound_messagelist.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('messageid', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('address', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table messageinbound_messagelist.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        // Conditionally launch create table for messageinbound_messagelist.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100700.0);
    }
    if ($oldversion < 2014100700.01) {
        // Define field visible to be added to cohort.
        $table = new xmldb_table('cohort');
        $field = new xmldb_field('visible', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'descriptionformat');
        // Conditionally launch add field visible.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100700.01);
    }
    if ($oldversion < 2014100800.0) {
        // Remove qformat_learnwise (unless it has manually been added back).
        if (!file_exists($CFG->dirroot . '/question/format/learnwise/format.php')) {
            unset_all_config_for_plugin('qformat_learnwise');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014100800.0);
    }
    if ($oldversion < 2014101001.0) {
        // Some blocks added themselves to the my/ home page, but they did not declare the
        // subpage of the default my home page. While the upgrade script has been fixed, this
        // upgrade script will fix the data that was wrongly added.
        // We only proceed if we can find the right entry from my_pages. Private => 1 refers to
        // the constant value MY_PAGE_PRIVATE.
        if ($systempage = $DB->get_record('my_pages', array('userid' => null, 'private' => 1))) {
            // Select the blocks there could have been automatically added. showinsubcontexts is hardcoded to 0
            // because it is possible for administrators to have forced it on the my/ page by adding it to the
            // system directly rather than updating the default my/ page.
            $blocks = array('course_overview', 'private_files', 'online_users', 'badges', 'calendar_month', 'calendar_upcoming');
            list($blocksql, $blockparams) = $DB->get_in_or_equal($blocks, SQL_PARAMS_NAMED);
            $select = "parentcontextid = :contextid\n                    AND pagetypepattern = :page\n                    AND showinsubcontexts = 0\n                    AND subpagepattern IS NULL\n                    AND blockname {$blocksql}";
            $params = array('contextid' => context_system::instance()->id, 'page' => 'my-index');
            $params = array_merge($params, $blockparams);
            $DB->set_field_select('block_instances', 'subpagepattern', $systempage->id, $select, $params);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014101001.0);
    }
    if ($oldversion < 2014102000.0) {
        // Define field aggregatesubcats to be dropped from grade_categories.
        $table = new xmldb_table('grade_categories');
        $field = new xmldb_field('aggregatesubcats');
        // Conditionally launch drop field aggregatesubcats.
        if ($dbman->field_exists($table, $field)) {
            $sql = 'SELECT DISTINCT courseid
                      FROM {grade_categories}
                     WHERE aggregatesubcats = ?';
            $courses = $DB->get_records_sql($sql, array(1));
            foreach ($courses as $course) {
                set_config('show_aggregatesubcats_upgrade_' . $course->courseid, 1);
                // Set each of the grade items to needing an update so that when the user visits the grade reports the
                // figures will be updated.
                $DB->set_field('grade_items', 'needsupdate', 1, array('courseid' => $course->courseid));
            }
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014102000.0);
    }
    if ($oldversion < 2014110300.0) {
        // Run script restoring missing folder records for draft file areas.
        upgrade_fix_missing_root_folders_draft();
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014110300.0);
    }
    // Moodle v2.8.0 release upgrade line.
    // Put any upgrade step following this.
    if ($oldversion < 2014111000.0) {
        // Coming from 2.7 or older, we need to flag the step minmaxgrade to be ignored.
        set_config('upgrade_minmaxgradestepignored', 1);
        // Coming from 2.7 or older, we need to flag the step for changing calculated grades to be regraded.
        set_config('upgrade_calculatedgradeitemsonlyregrade', 1);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014111000.0);
    }
    if ($oldversion < 2014120100.0) {
        // Define field sslverification to be added to mnet_host.
        $table = new xmldb_table('mnet_host');
        $field = new xmldb_field('sslverification', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'applicationid');
        // Conditionally launch add field sslverification.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014120100.0);
    }
    if ($oldversion < 2014120101.0) {
        // Define field component to be added to comments.
        $table = new xmldb_table('comments');
        $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'contextid');
        // Conditionally launch add field component.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014120101.0);
    }
    if ($oldversion < 2014120102.0) {
        // Define table user_password_history to be created.
        $table = new xmldb_table('user_password_history');
        // Adding fields to table user_password_history.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('hash', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table user_password_history.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
        // Conditionally launch create table for user_password_history.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2014120102.0);
    }
    if ($oldversion < 2015010800.01) {
        // Make sure the private files handler is not set to expire.
        $DB->set_field('messageinbound_handlers', 'defaultexpiration', 0, array('classname' => '\\core\\message\\inbound\\private_files_handler'));
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015010800.01);
    }
    if ($oldversion < 2015012600.0) {
        // If the site is using internal and external storage, or just external
        // storage, and the external path specified is empty we change the setting
        // to internal only. That is how the backup code is handling this
        // misconfiguration.
        $storage = (int) get_config('backup', 'backup_auto_storage');
        $folder = get_config('backup', 'backup_auto_destination');
        if ($storage !== 0 && empty($folder)) {
            set_config('backup_auto_storage', 0, 'backup');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015012600.0);
    }
    if ($oldversion < 2015012600.01) {
        // Convert calendar_lookahead to nearest new value.
        $value = $DB->get_field('config', 'value', array('name' => 'calendar_lookahead'));
        if ($value > 90) {
            set_config('calendar_lookahead', '120');
        } else {
            if ($value > 60 and $value < 90) {
                set_config('calendar_lookahead', '90');
            } else {
                if ($value > 30 and $value < 60) {
                    set_config('calendar_lookahead', '60');
                } else {
                    if ($value > 21 and $value < 30) {
                        set_config('calendar_lookahead', '30');
                    } else {
                        if ($value > 14 and $value < 21) {
                            set_config('calendar_lookahead', '21');
                        } else {
                            if ($value > 7 and $value < 14) {
                                set_config('calendar_lookahead', '14');
                            }
                        }
                    }
                }
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015012600.01);
    }
    if ($oldversion < 2015021100.0) {
        // Define field timemodified to be added to registration_hubs.
        $table = new xmldb_table('registration_hubs');
        $field = new xmldb_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'secret');
        // Conditionally launch add field timemodified.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015021100.0);
    }
    if ($oldversion < 2015022401.0) {
        // Define index useridfromto (not unique) to be added to message.
        $table = new xmldb_table('message');
        $index = new xmldb_index('useridfromto', XMLDB_INDEX_NOTUNIQUE, array('useridfrom', 'useridto'));
        // Conditionally launch add index useridfromto.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Define index useridfromto (not unique) to be added to message_read.
        $table = new xmldb_table('message_read');
        $index = new xmldb_index('useridfromto', XMLDB_INDEX_NOTUNIQUE, array('useridfrom', 'useridto'));
        // Conditionally launch add index useridfromto.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015022401.0);
    }
    if ($oldversion < 2015022500.0) {
        $table = new xmldb_table('user_devices');
        $index = new xmldb_index('uuid-userid', XMLDB_INDEX_NOTUNIQUE, array('uuid', 'userid'));
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        upgrade_main_savepoint(true, 2015022500.0);
    }
    if ($oldversion < 2015030400.0) {
        // We have long since switched to storing timemodified per hub rather than a single 'registered' timestamp.
        unset_config('registered');
        upgrade_main_savepoint(true, 2015030400.0);
    }
    if ($oldversion < 2015031100.0) {
        // Unset old config variable.
        unset_config('enabletgzbackups');
        upgrade_main_savepoint(true, 2015031100.0);
    }
    if ($oldversion < 2015031400.0) {
        // Define index useridfrom (not unique) to be dropped form message.
        $table = new xmldb_table('message');
        $index = new xmldb_index('useridfrom', XMLDB_INDEX_NOTUNIQUE, array('useridfrom'));
        // Conditionally launch drop index useridfrom.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Define index useridfrom (not unique) to be dropped form message_read.
        $table = new xmldb_table('message_read');
        $index = new xmldb_index('useridfrom', XMLDB_INDEX_NOTUNIQUE, array('useridfrom'));
        // Conditionally launch drop index useridfrom.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015031400.0);
    }
    if ($oldversion < 2015031900.01) {
        unset_config('crontime', 'registration');
        upgrade_main_savepoint(true, 2015031900.01);
    }
    if ($oldversion < 2015032000.0) {
        $table = new xmldb_table('badge_criteria');
        $field = new xmldb_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
        // Conditionally add description field to the badge_criteria table.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $field = new xmldb_field('descriptionformat', XMLDB_TYPE_INTEGER, 2, null, XMLDB_NOTNULL, null, 0);
        // Conditionally add description format field to the badge_criteria table.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        upgrade_main_savepoint(true, 2015032000.0);
    }
    if ($oldversion < 2015040200.01) {
        // Force uninstall of deleted tool.
        if (!file_exists("{$CFG->dirroot}/{$CFG->admin}/tool/timezoneimport")) {
            // Remove capabilities.
            capabilities_cleanup('tool_timezoneimport');
            // Remove all other associated config.
            unset_all_config_for_plugin('tool_timezoneimport');
        }
        upgrade_main_savepoint(true, 2015040200.01);
    }
    if ($oldversion < 2015040200.02) {
        // Define table timezone to be dropped.
        $table = new xmldb_table('timezone');
        // Conditionally launch drop table for timezone.
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        upgrade_main_savepoint(true, 2015040200.02);
    }
    if ($oldversion < 2015040200.03) {
        if (isset($CFG->timezone) and $CFG->timezone == 99) {
            // Migrate to real server timezone.
            unset_config('timezone');
        }
        upgrade_main_savepoint(true, 2015040200.03);
    }
    if ($oldversion < 2015040700.01) {
        $DB->delete_records('config_plugins', array('name' => 'requiremodintro'));
        upgrade_main_savepoint(true, 2015040700.01);
    }
    if ($oldversion < 2015040900.01) {
        // Add "My grades" to the user menu.
        $oldconfig = get_config('core', 'customusermenuitems');
        if (strpos("mygrades,grades|/grade/report/mygrades.php|grades", $oldconfig) === false) {
            $newconfig = "mygrades,grades|/grade/report/mygrades.php|grades\n" . $oldconfig;
            set_config('customusermenuitems', $newconfig);
        }
        upgrade_main_savepoint(true, 2015040900.01);
    }
    if ($oldversion < 2015040900.02) {
        // Update the default user menu (add preferences, remove my files and my badges).
        $oldconfig = get_config('core', 'customusermenuitems');
        // Add "My preferences" at the end.
        if (strpos($oldconfig, "mypreferences,moodle|/user/preference.php|preferences") === false) {
            $newconfig = $oldconfig . "\nmypreferences,moodle|/user/preferences.php|preferences";
        } else {
            $newconfig = $oldconfig;
        }
        // Remove my files.
        $newconfig = str_replace("myfiles,moodle|/user/files.php|download", "", $newconfig);
        // Remove my badges.
        $newconfig = str_replace("mybadges,badges|/badges/mybadges.php|award", "", $newconfig);
        // Remove holes.
        $newconfig = preg_replace('/\\n+/', "\n", $newconfig);
        $newconfig = preg_replace('/(\\r\\n)+/', "\n", $newconfig);
        set_config('customusermenuitems', $newconfig);
        upgrade_main_savepoint(true, 2015040900.02);
    }
    if ($oldversion < 2015050400.0) {
        $config = get_config('core', 'customusermenuitems');
        // Change "My preferences" in the user menu to "Preferences".
        $config = str_replace("mypreferences,moodle|/user/preferences.php|preferences", "preferences,moodle|/user/preferences.php|preferences", $config);
        // Change "My grades" in the user menu to "Grades".
        $config = str_replace("mygrades,grades|/grade/report/mygrades.php|grades", "grades,grades|/grade/report/mygrades.php|grades", $config);
        set_config('customusermenuitems', $config);
        upgrade_main_savepoint(true, 2015050400.0);
    }
    if ($oldversion < 2015050401.0) {
        // Make sure we have messages in the user menu because it's no longer in the nav tree.
        $oldconfig = get_config('core', 'customusermenuitems');
        $messagesconfig = "messages,message|/message/index.php|message";
        $preferencesconfig = "preferences,moodle|/user/preferences.php|preferences";
        // See if it exists.
        if (strpos($oldconfig, $messagesconfig) === false) {
            // See if preferences exists.
            if (strpos($oldconfig, "preferences,moodle|/user/preferences.php|preferences") !== false) {
                // Insert it before preferences.
                $newconfig = str_replace($preferencesconfig, $messagesconfig . "\n" . $preferencesconfig, $oldconfig);
            } else {
                // Custom config - we can only insert it at the end.
                $newconfig = $oldconfig . "\n" . $messagesconfig;
            }
            set_config('customusermenuitems', $newconfig);
        }
        upgrade_main_savepoint(true, 2015050401.0);
    }
    // Moodle v2.9.0 release upgrade line.
    // Put any upgrade step following this.
    if ($oldversion < 2015060400.02) {
        // Sites that were upgrading from 2.7 and older will ignore this step.
        if (empty($CFG->upgrade_minmaxgradestepignored)) {
            upgrade_minmaxgrade();
            // Flags this upgrade step as already run to prevent it from running multiple times.
            set_config('upgrade_minmaxgradestepignored', 1);
        }
        upgrade_main_savepoint(true, 2015060400.02);
    }
    if ($oldversion < 2015061900.0) {
        // MDL-49257. Changed the algorithm of calculating automatic weights of extra credit items.
        // Before the change, in case when grade category (in "Natural" agg. method) had items with
        // overridden weights, the automatic weight of extra credit items was illogical.
        // In order to prevent grades changes after the upgrade we need to freeze gradebook calculation
        // for the affected courses.
        // This script in included in each major version upgrade process so make sure we don't run it twice.
        if (empty($CFG->upgrade_extracreditweightsstepignored)) {
            upgrade_extra_credit_weightoverride();
            // To skip running the same script on the upgrade to the next major release.
            set_config('upgrade_extracreditweightsstepignored', 1);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015061900.0);
    }
    if ($oldversion < 2015062500.01) {
        // MDL-48239. Changed calculated grade items so that the maximum and minimum grade can be set.
        // If the changes are accepted and a regrade is done on the gradebook then some grades may change significantly.
        // This is here to freeze the gradebook in affected courses.
        // This script is included in each major version upgrade process so make sure we don't run it twice.
        if (empty($CFG->upgrade_calculatedgradeitemsignored)) {
            upgrade_calculated_grade_items();
            // To skip running the same script on the upgrade to the next major release.
            set_config('upgrade_calculatedgradeitemsignored', 1);
            // This config value is never used again.
            unset_config('upgrade_calculatedgradeitemsonlyregrade');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015062500.01);
    }
    if ($oldversion < 2015081300.01) {
        // Define field importtype to be added to grade_import_values.
        $table = new xmldb_table('grade_import_values');
        $field = new xmldb_field('importonlyfeedback', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'importer');
        // Conditionally launch add field importtype.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015081300.01);
    }
    if ($oldversion < 2015082400.0) {
        // Define table webdav_locks to be dropped.
        $table = new xmldb_table('webdav_locks');
        // Conditionally launch drop table for webdav_locks.
        if ($dbman->table_exists($table)) {
            $dbman->drop_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015082400.0);
    }
    if ($oldversion < 2015090200.0) {
        $table = new xmldb_table('message');
        // Define the deleted fields to be added to the message tables.
        $field1 = new xmldb_field('timeuserfromdeleted', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'timecreated');
        $field2 = new xmldb_field('timeusertodeleted', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'timecreated');
        $oldindex = new xmldb_index('useridfromto', XMLDB_INDEX_NOTUNIQUE, array('useridfrom', 'useridto'));
        $newindex = new xmldb_index('useridfromtodeleted', XMLDB_INDEX_NOTUNIQUE, array('useridfrom', 'useridto', 'timeuserfromdeleted', 'timeusertodeleted'));
        // Conditionally launch add field timeuserfromdeleted.
        if (!$dbman->field_exists($table, $field1)) {
            $dbman->add_field($table, $field1);
        }
        // Conditionally launch add field timeusertodeleted.
        if (!$dbman->field_exists($table, $field2)) {
            $dbman->add_field($table, $field2);
        }
        // Conditionally launch drop index useridfromto.
        if ($dbman->index_exists($table, $oldindex)) {
            $dbman->drop_index($table, $oldindex);
        }
        // Conditionally launch add index useridfromtodeleted.
        if (!$dbman->index_exists($table, $newindex)) {
            $dbman->add_index($table, $newindex);
        }
        // Now add them to the message_read table.
        $table = new xmldb_table('message_read');
        // Conditionally launch add field timeuserfromdeleted.
        if (!$dbman->field_exists($table, $field1)) {
            $dbman->add_field($table, $field1);
        }
        // Conditionally launch add field timeusertodeleted.
        if (!$dbman->field_exists($table, $field2)) {
            $dbman->add_field($table, $field2);
        }
        // Conditionally launch drop index useridfromto.
        if ($dbman->index_exists($table, $oldindex)) {
            $dbman->drop_index($table, $oldindex);
        }
        // Conditionally launch add index useridfromtodeleted.
        if (!$dbman->index_exists($table, $newindex)) {
            $dbman->add_index($table, $newindex);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015090200.0);
    }
    if ($oldversion < 2015090801.0) {
        // This upgrade script merges all tag instances pointing to the same course tag.
        // User id is no longer used for those tag instances.
        upgrade_course_tags();
        // If configuration variable "Show course tags" is set, disable the block
        // 'tags' because it can not be used for tagging courses any more.
        if (!empty($CFG->block_tags_showcoursetags)) {
            if ($record = $DB->get_record('block', array('name' => 'tags'), 'id, visible')) {
                if ($record->visible) {
                    $DB->update_record('block', array('id' => $record->id, 'visible' => 0));
                }
            }
        }
        // Define index idname (unique) to be dropped form tag (it's really weird).
        $table = new xmldb_table('tag');
        $index = new xmldb_index('idname', XMLDB_INDEX_UNIQUE, array('id', 'name'));
        // Conditionally launch drop index idname.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015090801.0);
    }
    if ($oldversion < 2015092200.0) {
        // Define index qtype (not unique) to be added to question.
        $table = new xmldb_table('question');
        $index = new xmldb_index('qtype', XMLDB_INDEX_NOTUNIQUE, array('qtype'));
        // Conditionally launch add index qtype.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015092200.0);
    }
    if ($oldversion < 2015092900.0) {
        // Rename backup_auto_keep setting to backup_auto_max_kept.
        $keep = get_config('backup', 'backup_auto_keep');
        if ($keep !== false) {
            set_config('backup_auto_max_kept', $keep, 'backup');
            unset_config('backup_auto_keep', 'backup');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015092900.0);
    }
    if ($oldversion < 2015100600.0) {
        // Define index notification (not unique) to be added to message_read.
        $table = new xmldb_table('message_read');
        $index = new xmldb_index('notificationtimeread', XMLDB_INDEX_NOTUNIQUE, array('notification', 'timeread'));
        // Conditionally launch add index notification.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2015100600.0);
    }
    if ($oldversion < 2015100800.01) {
        // The only flag for preventing all plugins installation features is
        // now $CFG->disableupdateautodeploy in config.php.
        unset_config('updateautodeploy');
        upgrade_main_savepoint(true, 2015100800.01);
    }
    // Moodle v3.0.0 release upgrade line.
    // Put any upgrade step following this.
    if ($oldversion < 2016011300.01) {
        // This is a big upgrade script. We create new table tag_coll and the field
        // tag.tagcollid pointing to it.
        // Define table tag_coll to be created.
        $table = new xmldb_table('tag_coll');
        // Adding fields to table tagcloud.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        $table->add_field('isdefault', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '5', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('searchable', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
        $table->add_field('customurl', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        // Adding keys to table tagcloud.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for tagcloud.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Table {tag}.
        // Define index name (unique) to be dropped form tag - we will replace it with index on (tagcollid,name) later.
        $table = new xmldb_table('tag');
        $index = new xmldb_index('name', XMLDB_INDEX_UNIQUE, array('name'));
        // Conditionally launch drop index name.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Define field tagcollid to be added to tag, we create it as null first and will change to notnull later.
        $table = new xmldb_table('tag');
        $field = new xmldb_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'userid');
        // Conditionally launch add field tagcloudid.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016011300.01);
    }
    if ($oldversion < 2016011300.02) {
        // Create a default tag collection if not exists and update the field tag.tagcollid to point to it.
        if (!($tcid = $DB->get_field_sql('SELECT id FROM {tag_coll} ORDER BY isdefault DESC, sortorder, id', null, IGNORE_MULTIPLE))) {
            $tcid = $DB->insert_record('tag_coll', array('isdefault' => 1, 'sortorder' => 0));
        }
        $DB->execute('UPDATE {tag} SET tagcollid = ? WHERE tagcollid IS NULL', array($tcid));
        // Define index tagcollname (unique) to be added to tag.
        $table = new xmldb_table('tag');
        $index = new xmldb_index('tagcollname', XMLDB_INDEX_UNIQUE, array('tagcollid', 'name'));
        $field = new xmldb_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'userid');
        // Conditionally launch add index tagcollname.
        if (!$dbman->index_exists($table, $index)) {
            // Launch change of nullability for field tagcollid.
            $dbman->change_field_notnull($table, $field);
            $dbman->add_index($table, $index);
        }
        // Define key tagcollid (foreign) to be added to tag.
        $table = new xmldb_table('tag');
        $key = new xmldb_key('tagcollid', XMLDB_KEY_FOREIGN, array('tagcollid'), 'tag_coll', array('id'));
        // Launch add key tagcloudid.
        $dbman->add_key($table, $key);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016011300.02);
    }
    if ($oldversion < 2016011300.03) {
        // Define table tag_area to be created.
        $table = new xmldb_table('tag_area');
        // Adding fields to table tag_area.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('enabled', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
        $table->add_field('tagcollid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('callback', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('callbackfile', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        // Adding keys to table tag_area.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('tagcollid', XMLDB_KEY_FOREIGN, array('tagcollid'), 'tag_coll', array('id'));
        // Adding indexes to table tag_area.
        $table->add_index('compitemtype', XMLDB_INDEX_UNIQUE, array('component', 'itemtype'));
        // Conditionally launch create table for tag_area.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016011300.03);
    }
    if ($oldversion < 2016011300.04) {
        // Define index itemtype-itemid-tagid-tiuserid (unique) to be dropped form tag_instance.
        $table = new xmldb_table('tag_instance');
        $index = new xmldb_index('itemtype-itemid-tagid-tiuserid', XMLDB_INDEX_UNIQUE, array('itemtype', 'itemid', 'tagid', 'tiuserid'));
        // Conditionally launch drop index itemtype-itemid-tagid-tiuserid.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016011300.04);
    }
    if ($oldversion < 2016011300.05) {
        $DB->execute("UPDATE {tag_instance} SET component = ? WHERE component IS NULL", array(''));
        // Changing nullability of field component on table tag_instance to not null.
        $table = new xmldb_table('tag_instance');
        $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'tagid');
        // Launch change of nullability for field component.
        $dbman->change_field_notnull($table, $field);
        // Changing type of field itemtype on table tag_instance to char.
        $table = new xmldb_table('tag_instance');
        $field = new xmldb_field('itemtype', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'component');
        // Launch change of type for field itemtype.
        $dbman->change_field_type($table, $field);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016011300.05);
    }
    if ($oldversion < 2016011300.06) {
        // Define index taggeditem (unique) to be added to tag_instance.
        $table = new xmldb_table('tag_instance');
        $index = new xmldb_index('taggeditem', XMLDB_INDEX_UNIQUE, array('component', 'itemtype', 'itemid', 'tiuserid', 'tagid'));
        // Conditionally launch add index taggeditem.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016011300.06);
    }
    if ($oldversion < 2016011300.07) {
        // Define index taglookup (not unique) to be added to tag_instance.
        $table = new xmldb_table('tag_instance');
        $index = new xmldb_index('taglookup', XMLDB_INDEX_NOTUNIQUE, array('itemtype', 'component', 'tagid', 'contextid'));
        // Conditionally launch add index taglookup.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016011300.07);
    }
    if ($oldversion < 2016011301.0) {
        // Force uninstall of deleted tool.
        if (!file_exists("{$CFG->dirroot}/webservice/amf")) {
            // Remove capabilities.
            capabilities_cleanup('webservice_amf');
            // Remove all other associated config.
            unset_all_config_for_plugin('webservice_amf');
        }
        upgrade_main_savepoint(true, 2016011301.0);
    }
    if ($oldversion < 2016011901.0) {
        // Convert calendar_lookahead to nearest new value.
        $transaction = $DB->start_delegated_transaction();
        // Count all users who curretly have that preference set (for progress bar).
        $total = $DB->count_records_select('user_preferences', "name = 'calendar_lookahead' AND value != '0'");
        $pbar = new progress_bar('upgradecalendarlookahead', 500, true);
        // Get all these users, one at a time.
        $rs = $DB->get_recordset_select('user_preferences', "name = 'calendar_lookahead' AND value != '0'");
        $i = 0;
        foreach ($rs as $userpref) {
            // Calculate and set new lookahead value.
            if ($userpref->value > 90) {
                $newvalue = 120;
            } else {
                if ($userpref->value > 60 and $userpref->value < 90) {
                    $newvalue = 90;
                } else {
                    if ($userpref->value > 30 and $userpref->value < 60) {
                        $newvalue = 60;
                    } else {
                        if ($userpref->value > 21 and $userpref->value < 30) {
                            $newvalue = 30;
                        } else {
                            if ($userpref->value > 14 and $userpref->value < 21) {
                                $newvalue = 21;
                            } else {
                                if ($userpref->value > 7 and $userpref->value < 14) {
                                    $newvalue = 14;
                                } else {
                                    $newvalue = $userpref->value;
                                }
                            }
                        }
                    }
                }
            }
            $DB->set_field('user_preferences', 'value', $newvalue, array('id' => $userpref->id));
            // Update progress.
            $i++;
            $pbar->update($i, $total, "Upgrading user preference settings - {$i}/{$total}.");
        }
        $rs->close();
        $transaction->allow_commit();
        upgrade_main_savepoint(true, 2016011901.0);
    }
    if ($oldversion < 2016020200.0) {
        // Define field isstandard to be added to tag.
        $table = new xmldb_table('tag');
        $field = new xmldb_field('isstandard', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'rawname');
        // Conditionally launch add field isstandard.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define index tagcolltype (not unique) to be dropped form tag.
        // This index is no longer created however it was present at some point and it's better to be safe and try to drop it.
        $index = new xmldb_index('tagcolltype', XMLDB_INDEX_NOTUNIQUE, array('tagcollid', 'tagtype'));
        // Conditionally launch drop index tagcolltype.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Define index tagcolltype (not unique) to be added to tag.
        $index = new xmldb_index('tagcolltype', XMLDB_INDEX_NOTUNIQUE, array('tagcollid', 'isstandard'));
        // Conditionally launch add index tagcolltype.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Define field tagtype to be dropped from tag.
        $field = new xmldb_field('tagtype');
        // Conditionally launch drop field tagtype and update isstandard.
        if ($dbman->field_exists($table, $field)) {
            $DB->execute("UPDATE {tag} SET isstandard=(CASE WHEN (tagtype = ?) THEN 1 ELSE 0 END)", array('official'));
            $dbman->drop_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016020200.0);
    }
    if ($oldversion < 2016020201.0) {
        // Define field showstandard to be added to tag_area.
        $table = new xmldb_table('tag_area');
        $field = new xmldb_field('showstandard', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'callbackfile');
        // Conditionally launch add field showstandard.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // By default set user area to hide standard tags. 2 = core_tag_tag::HIDE_STANDARD (can not use constant here).
        $DB->execute("UPDATE {tag_area} SET showstandard = ? WHERE itemtype = ? AND component = ?", array(2, 'user', 'core'));
        // Changing precision of field enabled on table tag_area to (1).
        $table = new xmldb_table('tag_area');
        $field = new xmldb_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'itemtype');
        // Launch change of precision for field enabled.
        $dbman->change_field_precision($table, $field);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016020201.0);
    }
    if ($oldversion < 2016021500.0) {
        $root = $CFG->tempdir . '/download';
        if (is_dir($root)) {
            // Fetch each repository type - include all repos, not just enabled.
            $repositories = $DB->get_records('repository', array(), '', 'type');
            foreach ($repositories as $id => $repository) {
                $directory = $root . '/repository_' . $repository->type;
                if (is_dir($directory)) {
                    fulldelete($directory);
                }
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016021500.0);
    }
    if ($oldversion < 2016021501.0) {
        // This could take a long time. Unfortunately, no way to know how long, and no way to do progress, so setting for 1 hour.
        upgrade_set_timeout(3600);
        // Define index userid-itemid (not unique) to be added to grade_grades_history.
        $table = new xmldb_table('grade_grades_history');
        $index = new xmldb_index('userid-itemid-timemodified', XMLDB_INDEX_NOTUNIQUE, array('userid', 'itemid', 'timemodified'));
        // Conditionally launch add index userid-itemid.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016021501.0);
    }
    if ($oldversion < 2016030103.0) {
        // MDL-50887. Implement plugins infrastructure for antivirus and create ClamAV plugin.
        // This routine moves core ClamAV configuration to plugin level.
        // If clamav was configured and enabled, enable the plugin.
        if (!empty($CFG->runclamonupload) && !empty($CFG->pathtoclam)) {
            set_config('antiviruses', 'clamav');
        } else {
            set_config('antiviruses', '');
        }
        if (isset($CFG->runclamonupload)) {
            // Just unset global configuration, we have already enabled the plugin
            // which implies that ClamAV will be used for scanning uploaded files.
            unset_config('runclamonupload');
        }
        // Move core ClamAV configuration settings to plugin.
        if (isset($CFG->pathtoclam)) {
            set_config('pathtoclam', $CFG->pathtoclam, 'antivirus_clamav');
            unset_config('pathtoclam');
        }
        if (isset($CFG->quarantinedir)) {
            set_config('quarantinedir', $CFG->quarantinedir, 'antivirus_clamav');
            unset_config('quarantinedir');
        }
        if (isset($CFG->clamfailureonupload)) {
            set_config('clamfailureonupload', $CFG->clamfailureonupload, 'antivirus_clamav');
            unset_config('clamfailureonupload');
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016030103.0);
    }
    if ($oldversion < 2016030400.01) {
        // Add the new services field.
        $table = new xmldb_table('external_functions');
        $field = new xmldb_field('services', XMLDB_TYPE_CHAR, '1333', null, null, null, null, 'capabilities');
        // Conditionally launch add field services.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016030400.01);
    }
    if ($oldversion < 2016041500.5) {
        // Define table competency to be created.
        $table = new xmldb_table('competency');
        // Adding fields to table competency.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('competencyframeworkid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('parentid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('path', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('ruletype', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('ruleoutcome', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('ruleconfig', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('scaleid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('scaleconfiguration', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        // Adding keys to table competency.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency.
        $table->add_index('idnumberframework', XMLDB_INDEX_UNIQUE, array('competencyframeworkid', 'idnumber'));
        $table->add_index('ruleoutcome', XMLDB_INDEX_NOTUNIQUE, array('ruleoutcome'));
        // Conditionally launch create table for competency.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.5);
    }
    if ($oldversion < 2016041500.51) {
        // Define table competency_coursecompsetting to be created.
        $table = new xmldb_table('competency_coursecompsetting');
        // Adding fields to table competency_coursecompsetting.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('pushratingstouserplans', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        // Adding keys to table competency_coursecompsetting.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('courseidlink', XMLDB_KEY_FOREIGN_UNIQUE, array('courseid'), 'course', array('id'));
        // Conditionally launch create table for competency_coursecompsetting.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.51);
    }
    if ($oldversion < 2016041500.52) {
        // Define table competency_framework to be created.
        $table = new xmldb_table('competency_framework');
        // Adding fields to table competency_framework.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('scaleid', XMLDB_TYPE_INTEGER, '11', null, null, null, null);
        $table->add_field('scaleconfiguration', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        $table->add_field('visible', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
        $table->add_field('taxonomies', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        // Adding keys to table competency_framework.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_framework.
        $table->add_index('idnumber', XMLDB_INDEX_UNIQUE, array('idnumber'));
        // Conditionally launch create table for competency_framework.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.52);
    }
    if ($oldversion < 2016041500.53) {
        // Define table competency_coursecomp to be created.
        $table = new xmldb_table('competency_coursecomp');
        // Adding fields to table competency_coursecomp.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('ruleoutcome', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_coursecomp.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('courseidlink', XMLDB_KEY_FOREIGN, array('courseid'), 'course', array('id'));
        $table->add_key('competencyid', XMLDB_KEY_FOREIGN, array('competencyid'), 'competency_competency', array('id'));
        // Adding indexes to table competency_coursecomp.
        $table->add_index('courseidruleoutcome', XMLDB_INDEX_NOTUNIQUE, array('courseid', 'ruleoutcome'));
        $table->add_index('courseidcompetencyid', XMLDB_INDEX_UNIQUE, array('courseid', 'competencyid'));
        // Conditionally launch create table for competency_coursecomp.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.53);
    }
    if ($oldversion < 2016041500.54) {
        // Define table competency_plan to be created.
        $table = new xmldb_table('competency_plan');
        // Adding fields to table competency_plan.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('templateid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('origtemplateid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('status', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null);
        $table->add_field('duedate', XMLDB_TYPE_INTEGER, '10', null, null, null, '0');
        $table->add_field('reviewerid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_plan.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_plan.
        $table->add_index('useridstatus', XMLDB_INDEX_NOTUNIQUE, array('userid', 'status'));
        $table->add_index('templateid', XMLDB_INDEX_NOTUNIQUE, array('templateid'));
        $table->add_index('statusduedate', XMLDB_INDEX_NOTUNIQUE, array('status', 'duedate'));
        // Conditionally launch create table for competency_plan.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.54);
    }
    if ($oldversion < 2016041500.55) {
        // Define table competency_template to be created.
        $table = new xmldb_table('competency_template');
        // Adding fields to table competency_template.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('shortname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('visible', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1');
        $table->add_field('duedate', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        // Adding keys to table competency_template.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for competency_template.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.55);
    }
    if ($oldversion < 2016041500.56) {
        // Define table competency_templatecomp to be created.
        $table = new xmldb_table('competency_templatecomp');
        // Adding fields to table competency_templatecomp.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('templateid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        // Adding keys to table competency_templatecomp.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('templateidlink', XMLDB_KEY_FOREIGN, array('templateid'), 'competency_template', array('id'));
        $table->add_key('competencyid', XMLDB_KEY_FOREIGN, array('competencyid'), 'competency_competency', array('id'));
        // Conditionally launch create table for competency_templatecomp.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.56);
    }
    if ($oldversion < 2016041500.57) {
        // Define table competency_templatecohort to be created.
        $table = new xmldb_table('competency_templatecohort');
        // Adding fields to table competency_templatecohort.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('templateid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('cohortid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_templatecohort.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_templatecohort.
        $table->add_index('templateid', XMLDB_INDEX_NOTUNIQUE, array('templateid'));
        $table->add_index('templatecohortids', XMLDB_INDEX_UNIQUE, array('templateid', 'cohortid'));
        // Conditionally launch create table for competency_templatecohort.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.57);
    }
    if ($oldversion < 2016041500.58) {
        // Define table competency_relatedcomp to be created.
        $table = new xmldb_table('competency_relatedcomp');
        // Adding fields to table competency_relatedcomp.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('relatedcompetencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_relatedcomp.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for competency_relatedcomp.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.58);
    }
    if ($oldversion < 2016041500.59) {
        // Define table competency_usercomp to be created.
        $table = new xmldb_table('competency_usercomp');
        // Adding fields to table competency_usercomp.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('status', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('reviewerid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('proficiency', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_usercomp.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_usercomp.
        $table->add_index('useridcompetency', XMLDB_INDEX_UNIQUE, array('userid', 'competencyid'));
        // Conditionally launch create table for competency_usercomp.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.59);
    }
    if ($oldversion < 2016041500.6) {
        // Define table competency_usercompcourse to be created.
        $table = new xmldb_table('competency_usercompcourse');
        // Adding fields to table competency_usercompcourse.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('proficiency', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_usercompcourse.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_usercompcourse.
        $table->add_index('useridcoursecomp', XMLDB_INDEX_UNIQUE, array('userid', 'courseid', 'competencyid'));
        // Conditionally launch create table for competency_usercompcourse.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.6);
    }
    if ($oldversion < 2016041500.61) {
        // Define table competency_usercompplan to be created.
        $table = new xmldb_table('competency_usercompplan');
        // Adding fields to table competency_usercompplan.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('planid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('proficiency', XMLDB_TYPE_INTEGER, '2', null, null, null, null);
        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_usercompplan.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_usercompplan.
        $table->add_index('usercompetencyplan', XMLDB_INDEX_UNIQUE, array('userid', 'competencyid', 'planid'));
        // Conditionally launch create table for competency_usercompplan.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.61);
    }
    if ($oldversion < 2016041500.62) {
        // Define table competency_plancomp to be created.
        $table = new xmldb_table('competency_plancomp');
        // Adding fields to table competency_plancomp.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('planid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_plancomp.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_plancomp.
        $table->add_index('planidcompetencyid', XMLDB_INDEX_UNIQUE, array('planid', 'competencyid'));
        // Conditionally launch create table for competency_plancomp.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.62);
    }
    if ($oldversion < 2016041500.63) {
        // Define table competency_evidence to be created.
        $table = new xmldb_table('competency_evidence');
        // Adding fields to table competency_evidence.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('usercompetencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('action', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
        $table->add_field('actionuserid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('descidentifier', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('desccomponent', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('desca', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('url', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        $table->add_field('grade', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
        $table->add_field('note', XMLDB_TYPE_TEXT, null, null, null, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_evidence.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_evidence.
        $table->add_index('usercompetencyid', XMLDB_INDEX_NOTUNIQUE, array('usercompetencyid'));
        // Conditionally launch create table for competency_evidence.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.63);
    }
    if ($oldversion < 2016041500.64) {
        // Define table competency_userevidence to be created.
        $table = new xmldb_table('competency_userevidence');
        // Adding fields to table competency_userevidence.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('name', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
        $table->add_field('description', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        $table->add_field('descriptionformat', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null);
        $table->add_field('url', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_userevidence.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_userevidence.
        $table->add_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid'));
        // Conditionally launch create table for competency_userevidence.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.64);
    }
    if ($oldversion < 2016041500.65) {
        // Define table competency_userevidencecomp to be created.
        $table = new xmldb_table('competency_userevidencecomp');
        // Adding fields to table competency_userevidencecomp.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('userevidenceid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_userevidencecomp.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table competency_userevidencecomp.
        $table->add_index('userevidenceid', XMLDB_INDEX_NOTUNIQUE, array('userevidenceid'));
        $table->add_index('userevidencecompids', XMLDB_INDEX_UNIQUE, array('userevidenceid', 'competencyid'));
        // Conditionally launch create table for competency_userevidencecomp.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.65);
    }
    if ($oldversion < 2016041500.66) {
        // Define table competency_modulecomp to be created.
        $table = new xmldb_table('competency_modulecomp');
        // Adding fields to table competency_modulecomp.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('cmid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('sortorder', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('competencyid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('ruleoutcome', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table competency_modulecomp.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        $table->add_key('cmidkey', XMLDB_KEY_FOREIGN, array('cmid'), 'course_modules', array('id'));
        $table->add_key('competencyidkey', XMLDB_KEY_FOREIGN, array('competencyid'), 'competency_competency', array('id'));
        // Adding indexes to table competency_modulecomp.
        $table->add_index('cmidruleoutcome', XMLDB_INDEX_NOTUNIQUE, array('cmid', 'ruleoutcome'));
        $table->add_index('cmidcompetencyid', XMLDB_INDEX_UNIQUE, array('cmid', 'competencyid'));
        // Conditionally launch create table for competency_modulecomp.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016041500.66);
    }
    if ($oldversion < 2016042100.0) {
        // Update all countries to upper case.
        $DB->execute("UPDATE {user} SET country = UPPER(country)");
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016042100.0);
    }
    if ($oldversion < 2016042600.01) {
        $deprecatedwebservices = ['moodle_course_create_courses', 'moodle_course_get_courses', 'moodle_enrol_get_enrolled_users', 'moodle_enrol_get_users_courses', 'moodle_enrol_manual_enrol_users', 'moodle_file_get_files', 'moodle_file_upload', 'moodle_group_add_groupmembers', 'moodle_group_create_groups', 'moodle_group_delete_groupmembers', 'moodle_group_delete_groups', 'moodle_group_get_course_groups', 'moodle_group_get_groupmembers', 'moodle_group_get_groups', 'moodle_message_send_instantmessages', 'moodle_notes_create_notes', 'moodle_role_assign', 'moodle_role_unassign', 'moodle_user_create_users', 'moodle_user_delete_users', 'moodle_user_get_course_participants_by_id', 'moodle_user_get_users_by_courseid', 'moodle_user_get_users_by_id', 'moodle_user_update_users', 'core_grade_get_definitions', 'core_user_get_users_by_id', 'moodle_webservice_get_siteinfo', 'mod_forum_get_forum_discussions'];
        list($insql, $params) = $DB->get_in_or_equal($deprecatedwebservices);
        $DB->delete_records_select('external_functions', "name {$insql}", $params);
        $DB->delete_records_select('external_services_functions', "functionname {$insql}", $params);
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016042600.01);
    }
    if ($oldversion < 2016051300.0) {
        // Add a default competency rating scale.
        make_competence_scale();
        // Savepoint reached.
        upgrade_main_savepoint(true, 2016051300.0);
    }
    if ($oldversion < 2016051700.01) {
        // This script is included in each major version upgrade process (3.0, 3.1) so make sure we don't run it twice.
        if (empty($CFG->upgrade_letterboundarycourses)) {
            // MDL-45390. If a grade is being displayed with letters and the grade boundaries are not being adhered to properly
            // then this course will also be frozen.
            // If the changes are accepted then the display of some grades may change.
            // This is here to freeze the gradebook in affected courses.
            upgrade_course_letter_boundary();
            // To skip running the same script on the upgrade to the next major version release.
            set_config('upgrade_letterboundarycourses', 1);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016051700.01);
    }
    // Moodle v3.1.0 release upgrade line.
    // Put any upgrade step following this.
    if ($oldversion < 2016081700.0) {
        // If someone is emotionally attached to it let's leave the config (basically the version) there.
        if (!file_exists($CFG->dirroot . '/report/search/classes/output/form.php')) {
            unset_all_config_for_plugin('report_search');
        }
        // Savepoint reached.
        upgrade_main_savepoint(true, 2016081700.0);
    }
    if ($oldversion < 2016081700.02) {
        // Default schedule values.
        $hour = 0;
        $minute = 0;
        // Get the old settings.
        if (isset($CFG->statsruntimestarthour)) {
            $hour = $CFG->statsruntimestarthour;
        }
        if (isset($CFG->statsruntimestartminute)) {
            $minute = $CFG->statsruntimestartminute;
        }
        // Retrieve the scheduled task record first.
        $stattask = $DB->get_record('task_scheduled', array('component' => 'moodle', 'classname' => '\\core\\task\\stats_cron_task'));
        // Don't touch customised scheduling.
        if ($stattask && !$stattask->customised) {
            $nextruntime = mktime($hour, $minute, 0, date('m'), date('d'), date('Y'));
            if ($nextruntime < $stattask->lastruntime) {
                // Add 24 hours to the next run time.
                $newtime = new DateTime();
                $newtime->setTimestamp($nextruntime);
                $newtime->add(new DateInterval('P1D'));
                $nextruntime = $newtime->getTimestamp();
            }
            $stattask->nextruntime = $nextruntime;
            $stattask->minute = $minute;
            $stattask->hour = $hour;
            $stattask->customised = 1;
            $DB->update_record('task_scheduled', $stattask);
        }
        // These settings are no longer used.
        unset_config('statsruntimestarthour');
        unset_config('statsruntimestartminute');
        unset_config('statslastexecution');
        upgrade_main_savepoint(true, 2016081700.02);
    }
    if ($oldversion < 2016082200.0) {
        // An upgrade step to remove any duplicate stamps, within the same context, in the question_categories table, and to
        // add a unique index to (contextid, stamp) to avoid future stamp duplication. See MDL-54864.
        // Extend the execution time limit of the script to 2 hours.
        upgrade_set_timeout(7200);
        // This SQL fetches the id of those records which have duplicate stamps within the same context.
        // This doesn't return the original record within the context, from which the duplicate stamps were likely created.
        $fromclause = "FROM (\n                        SELECT min(id) AS minid, contextid, stamp\n                            FROM {question_categories}\n                            GROUP BY contextid, stamp\n                        ) minid\n                        JOIN {question_categories} qc\n                            ON qc.contextid = minid.contextid AND qc.stamp = minid.stamp AND qc.id > minid.minid";
        // Get the total record count - used for the progress bar.
        $countduplicatessql = "SELECT count(qc.id) {$fromclause}";
        $total = $DB->count_records_sql($countduplicatessql);
        // Get the records themselves.
        $getduplicatessql = "SELECT qc.id {$fromclause} ORDER BY minid";
        $rs = $DB->get_recordset_sql($getduplicatessql);
        // For each duplicate, update the stamp to a new random value.
        $i = 0;
        $pbar = new progress_bar('updatequestioncategorystamp', 500, true);
        foreach ($rs as $record) {
            // Generate a new, unique stamp and update the record.
            do {
                $newstamp = make_unique_id_code();
            } while (isset($usedstamps[$newstamp]));
            $usedstamps[$newstamp] = 1;
            $DB->set_field('question_categories', 'stamp', $newstamp, array('id' => $record->id));
            // Update progress.
            $i++;
            $pbar->update($i, $total, "Updating duplicate question category stamp - {$i}/{$total}.");
        }
        unset($usedstamps);
        // The uniqueness of each (contextid, stamp) pair is now guaranteed, so add the unique index to stop future duplicates.
        $table = new xmldb_table('question_categories');
        $index = new xmldb_index('contextidstamp', XMLDB_INDEX_UNIQUE, array('contextid', 'stamp'));
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Savepoint reached.
        upgrade_main_savepoint(true, 2016082200.0);
    }
    if ($oldversion < 2016091900.0) {
        // Removing the themes from core.
        $themes = array('base', 'canvas');
        foreach ($themes as $key => $theme) {
            if (check_dir_exists($CFG->dirroot . '/theme/' . $theme, false)) {
                // Ignore the themes that have been re-downloaded.
                unset($themes[$key]);
            }
        }
        if (!empty($themes)) {
            // Hacky emulation of plugin uninstallation.
            foreach ($themes as $theme) {
                unset_all_config_for_plugin('theme_' . $theme);
            }
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016091900.0);
    }
    if ($oldversion < 2016091900.02) {
        // Define index attemptstepid-name (unique) to be dropped from question_attempt_step_data.
        $table = new xmldb_table('question_attempt_step_data');
        $index = new xmldb_index('attemptstepid-name', XMLDB_INDEX_UNIQUE, array('attemptstepid', 'name'));
        // Conditionally launch drop index attemptstepid-name.
        if ($dbman->index_exists($table, $index)) {
            $dbman->drop_index($table, $index);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016091900.02);
    }
    if ($oldversion < 2016100300.0) {
        unset_config('enablecssoptimiser');
        upgrade_main_savepoint(true, 2016100300.0);
    }
    if ($oldversion < 2016100501.0) {
        // Define field enddate to be added to course.
        $table = new xmldb_table('course');
        $field = new xmldb_field('enddate', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'startdate');
        // Conditionally launch add field enddate.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016100501.0);
    }
    if ($oldversion < 2016101100.0) {
        // Define field component to be added to message.
        $table = new xmldb_table('message');
        $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'timeusertodeleted');
        // Conditionally launch add field component.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field eventtype to be added to message.
        $field = new xmldb_field('eventtype', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'component');
        // Conditionally launch add field eventtype.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016101100.0);
    }
    if ($oldversion < 2016101101.0) {
        // Define field component to be added to message_read.
        $table = new xmldb_table('message_read');
        $field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'timeusertodeleted');
        // Conditionally launch add field component.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field eventtype to be added to message_read.
        $field = new xmldb_field('eventtype', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'component');
        // Conditionally launch add field eventtype.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016101101.0);
    }
    if ($oldversion < 2016101401.0) {
        // Clean up repository_alfresco config unless plugin has been manually installed.
        if (!file_exists($CFG->dirroot . '/repository/alfresco/lib.php')) {
            // Remove capabilities.
            capabilities_cleanup('repository_alfresco');
            // Clean config.
            unset_all_config_for_plugin('repository_alfresco');
        }
        // Savepoint reached.
        upgrade_main_savepoint(true, 2016101401.0);
    }
    if ($oldversion < 2016101401.02) {
        $table = new xmldb_table('external_tokens');
        $field = new xmldb_field('privatetoken', XMLDB_TYPE_CHAR, '64', null, null, null, null);
        // Conditionally add privatetoken field to the external_tokens table.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Main savepoint reached.
        upgrade_main_savepoint(true, 2016101401.02);
    }
    return true;
}
Example #16
0
 /**
  * Creates a new category with given params
  *
  */
 function add_category($newparent, $newcategory, $newinfo)
 {
     if (empty($newcategory)) {
         print_error('categorynamecantbeblank', 'quiz');
     }
     list($parentid, $contextid) = explode(',', $newparent);
     //moodle_form makes sure select element output is legal no need for further cleaning
     require_capability('moodle/question:managecategory', get_context_instance_by_id($contextid));
     if ($parentid) {
         if (!(get_field('question_categories', 'contextid', 'id', $parentid) == $contextid)) {
             error("Could not insert the new question category '{$newcategory}' illegal contextid '{$contextid}'.");
         }
     }
     $cat = new object();
     $cat->parent = $parentid;
     $cat->contextid = $contextid;
     $cat->name = $newcategory;
     $cat->info = $newinfo;
     $cat->sortorder = 999;
     $cat->stamp = make_unique_id_code();
     if (!insert_record("question_categories", $cat)) {
         error("Could not insert the new question category '{$newcategory}'");
     } else {
         redirect($this->pageurl->out());
         //always redirect after successful action
     }
 }
Example #17
0
 function importprocess($filename)
 {
     global $CFG, $USER, $strimportquestions, $form, $question_category, $category, $COURSE, $hostname, $mdapath, $mdbpath;
     if (PHP_OS == "Linux" and isset($hostname)) {
         $hostname = trim($hostname);
         // test the ODBC socket server connection
         // if failure, unset hostname and set hostname_access_error
         $question_categories = $this->getquestioncategories($mdbpath, $mdapath, $hostname);
         if (!$question_categories) {
             $hostname_access_error = $hostname . " ";
             unset($hostname);
         } else {
             $hostname_access_error = 0;
         }
     }
     if (PHP_OS == "Linux" and !isset($hostname)) {
         // copy the file to a semi-permanent location
         if (!($basedir = make_upload_directory("{$COURSE->id}"))) {
             error("The site administrator needs to fix the file permissions for the data directory");
         }
         if (!isset($hostname_access_error)) {
             $bname = basename($filename);
             $cleanfilename = clean_filename($bname);
             if ($cleanfilename) {
                 $newfile = "{$basedir}/{$cleanfilename}";
                 if (move_uploaded_file($filename, $newfile)) {
                     chmod($newfile, 0666);
                     clam_log_upload($newfile, $COURSE);
                 } else {
                     notify(get_string("uploadproblem", "", $filename));
                 }
             }
             $filename = $newfile;
         }
         print_heading_with_help($strimportquestions, "import", "quiz");
         print_simple_box_start("center");
         if ($hostname_access_error) {
             notify("couldn't connect to ODBC Socket Server on " . $hostname_access_error);
         }
         echo "<form method=\"post\" action=\"import.php\">";
         echo '<fieldset class="invisiblefieldset">';
         echo "<table cellpadding=\"5\">";
         echo "<tr><td align=\"right\">";
         echo "What is the hostname or IP address of the ODBC Socket Server:</td><td>";
         echo " <input name=\"hostname\" type=\"text\" size=\"50\" value=\"" . stripslashes($hostname_access_error) . "\" />";
         echo " <input name=\"filename\" type=\"hidden\" value=\"" . $filename . "\" />";
         echo " <input name=\"category\" type=\"hidden\" value=\"" . $category->id . "\" />";
         echo " <input name=\"format\" type=\"hidden\" value=\"" . $form->format . "\" />";
         echo "</td><td>&nbsp;</td></tr>";
         echo "<tr><td align=\"right\">";
         echo "What is the location of the database (.mdb file) on the Socket Server:</td><td>";
         echo " <input name=\"mdbpath\" type=\"text\" size=\"50\" value=\"" . stripslashes($mdbpath) . "\" />";
         echo "</td><td>&nbsp;</td></tr>";
         echo "<tr><td align=\"right\">";
         echo "What is the location of the system database (System.mda file) on the Socket Server:</td><td>";
         echo " <input name=\"mdapath\" type=\"text\" size=\"50\" value=\"" . stripslashes($mdapath) . "\" />";
         echo "</td><td>&nbsp;</td></tr>";
         echo "<tr><td>&nbsp;</td><td>";
         echo " <input type=\"submit\" name=\"save\" value=\"Connect to Server\" />";
         echo "</td></tr>";
         echo "</table>";
         echo '</fieldset>';
         echo "</form>";
         print_simple_box_end();
         print_footer($COURSE);
         exit;
     }
     // we get here if running windows or after connect to ODBC socket server on linux
     //
     // this generates the page to choose categories of questions to import
     //
     if (!isset($question_category)) {
         if (PHP_OS == "WINNT") {
             // copy the file to a semi-permanent location
             if (!($basedir = make_upload_directory("{$COURSE->id}"))) {
                 error("The site administrator needs to fix the file permissions for the data directory");
             }
             $bname = basename($filename);
             $cleanfilename = clean_filename($bname);
             if ($cleanfilename) {
                 $newfile = "{$basedir}/{$cleanfilename}";
                 if (move_uploaded_file($filename, $newfile)) {
                     chmod($newfile, 0666);
                     clam_log_upload($newfile, $COURSE);
                 } else {
                     notify(get_string("uploadproblem", "", $filename));
                 }
             }
             $filename = $newfile;
         }
         // end of file copy
         // don't have to do this on linux, since it's alreay been done in the test above
         if (PHP_OS == "WINNT") {
             $question_categories = $this->getquestioncategories($filename);
         }
         // print the intermediary form
         if (!($categories = question_category_options($COURSE->id, true))) {
             error("No categories!");
         }
         print_heading_with_help($strimportquestions, "import", "quiz");
         print_simple_box_start("center");
         echo "<form method=\"post\" action=\"import.php\">";
         echo '<fieldset class="invisiblefieldset">';
         echo "<table cellpadding=\"5\">";
         echo "<tr><td align=\"right\">";
         echo "Choose a category of questions to import:</td><td>";
         asort($question_categories);
         choose_from_menu($question_categories, "question_category", "All Categories", "All Categories", "", "allcategories");
         echo " <input name=\"filename\" type=\"hidden\" value=\"" . $filename . "\" />";
         echo " <input name=\"category\" type=\"hidden\" value=\"" . $category->id . "\" />";
         echo " <input name=\"format\" type=\"hidden\" value=\"" . $form->format . "\" />";
         if (PHP_OS == "Linux") {
             echo " <input name=\"hostname\" type=\"hidden\" value=\"" . stripslashes(trim($hostname)) . "\" />";
             echo " <input name=\"mdbpath\" type=\"hidden\" value=\"" . stripslashes($mdbpath) . "\" />";
             echo " <input name=\"mdapath\" type=\"hidden\" value=\"" . stripslashes($mdapath) . "\" />";
         }
         echo "</td><td>&nbsp;</td>";
         echo "</tr><tr><td>&nbsp;</td><td>";
         echo " <input type=\"submit\" name=\"save\" value=\"Import Questions\" />";
         echo "</td></tr>";
         echo "</table>";
         echo '</fieldset>';
         echo "</form>";
         print_simple_box_end();
         print_footer($COURSE);
         exit;
     }
     //
     // this is the main import section
     //
     notify("Importing questions");
     if (PHP_OS == "Linux") {
         $hostname = trim($hostname);
         $records = $this->getquestions($mdbpath, $question_category, $mdapath, $hostname);
     } else {
         $records = $this->getquestions($filename, $question_category);
     }
     foreach ($records as $qrec) {
         $question = $this->defaultquestion();
         if ($qrec[9] != "") {
             $question->image = $qrec[9];
         }
         //  0   Selected
         //  1   PracticeTestOK?
         //  2   QuestionText
         //  3   QuestionType
         //  4   Option1Text
         //  5   Option2Text
         //  6   Option3Text
         //  7   Option4Text
         //  8   CorrectAnswer
         //  9   Graphic
         //  10  Module
         //  11  ChapterNumber
         //  12  PageNumber
         $ref = "Answer can be found in chapter " . $qrec[11] . ", page " . $qrec[12] . ".";
         switch ($qrec[3]) {
             case 1:
                 $question->qtype = MULTICHOICE;
                 // MULTICHOICE, SHORTANSWER, TRUEFALSE
                 //          echo "<pre>";echo htmlspecialchars($qrec[2]); echo "</pre>";
                 $question->questiontext = addslashes(trim($qrec[2]));
                 //          echo "<pre>";echo $question->questiontext; echo "</pre>";
                 $question->name = preg_replace("/<br />/", "", $question->questiontext);
                 $question->single = 1;
                 // Only one answer is allowed -- used for multiple choicers
                 $fractionset = 0;
                 for ($i = 4; $i <= 7; $i++) {
                     if ($qrec[$i] != "") {
                         $question->answer[$i - 3] = addslashes($qrec[$i]);
                         if ($qrec[8] == $i - 3) {
                             // if this is the index of CorrectAnswer
                             $question->fraction[$i - 3] = 1;
                             $fractionset = 1;
                         } else {
                             $question->fraction[$i - 3] = 0;
                         }
                         $question->feedback[$i - 3] = ($qrec[8] == $i - 3 ? "Correct. " : "Incorrect. ") . $ref;
                     }
                 }
                 if ($fractionset == 0) {
                     $question->fraction[1] = 1;
                 }
                 break;
             case 2:
                 // TRUE FALSE
                 $question->qtype = TRUEFALSE;
                 $question->questiontext = addslashes(trim($qrec[2]));
                 $question->name = preg_replace("/<br />/", "", $question->questiontext);
                 // for TF, $question->answer should be 1 for true, 0 for false
                 if ($qrec[8] == "T") {
                     $question->answer = 1;
                 } else {
                     $question->answer = 0;
                 }
                 // for TF, use $question->feedbacktrue and feedbackfalse
                 $question->feedbacktrue = ($qrec[8] == "T" ? "Correct. " : "Incorrect. ") . $ref;
                 $question->feedbackfalse = ($qrec[8] == "F" ? "Correct. " : "Incorrect. ") . $ref;
                 break;
             case 3:
                 $question->qtype = SHORTANSWER;
                 $question->questiontext = addslashes(trim($qrec[2]));
                 //          echo "<pre>";echo $question->questiontext; echo "</pre>";
                 $question->name = preg_replace("/<br />/", "", $question->questiontext);
                 $question->usecase = 0;
                 // Ignore case -- for SHORT ANSWER questions
                 $answers = explode("~", $qrec[8]);
                 $question->answer[0] = " ";
                 $question->fraction[0] = 1;
                 for ($i = 0; $i < count($answers); $i++) {
                     $question->answer[$i] = addslashes(trim($answers[$i]));
                     $question->feedback[$i] = $ref;
                     $question->fraction[$i] = 1;
                     // 1 for 100%, 0 for none or somewhere in between
                 }
                 break;
             case 4:
                 $question = 0;
                 notify("Cannot use essay questions - skipping question " . $qrec[2] . " " . $ref);
                 break;
             default:
                 $question = 0;
                 notify("Misformatted Record.  Question Skipped.");
                 break;
         }
         if ($question) {
             $questions[] = $question;
         }
     }
     $count = 0;
     // process all the questions
     if (PHP_OS == "WINNT") {
         $filename = str_replace("\\\\", "\\", $filename);
         $filename = str_replace("/", "\\", $filename);
     }
     foreach ($questions as $question) {
         // Process and store each question
         $count++;
         echo "<hr /><p><b>{$count}</b>. " . stripslashes($question->questiontext) . "</p>";
         $question->category = $this->category->id;
         $question->stamp = make_unique_id_code();
         // Set the unique code (not to be changed)
         $question->createdby = $USER->id;
         $question->timecreated = time();
         if (!($question->id = insert_record("question", $question))) {
             error("Could not insert new question!");
         }
         $this->questionids[] = $question->id;
         // Now to save all the answers and type-specific options
         $result = save_question_options($question);
         if (!empty($result->error)) {
             notify($result->error);
             $this->deletedatabase($filename);
             return false;
         }
         if (!empty($result->notice)) {
             notify($result->notice);
             $this->deletedatabase($filename);
             return true;
         }
         // Give the question a unique version stamp determined by question_hash()
         set_field('question', 'version', question_hash($question), 'id', $question->id);
     }
     $this->deletedatabase($filename);
     return true;
 }
Example #18
0
function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
        $includesubcategories) {
    global $DB;

    $category = $DB->get_record('question_categories', array('id' => $categoryid));
    if (!$category) {
        print_error('invalidcategoryid', 'error');
    }

    $catcontext = get_context_instance_by_id($category->contextid);
    require_capability('moodle/question:useall', $catcontext);

    // Find existing random questions in this category that are
    // not used by any quiz.
    if ($existingquestions = $DB->get_records_sql(
            "SELECT q.id, q.qtype FROM {question} q
            WHERE qtype = 'random'
                AND category = ?
                AND " . $DB->sql_compare_text('questiontext') . " = ?
                AND NOT EXISTS (
                        SELECT *
                          FROM {quiz_question_instances}
                         WHERE question = q.id)
            ORDER BY id", array($category->id, $includesubcategories))) {
        // Take as many of these as needed.
        while (($existingquestion = array_shift($existingquestions)) && $number > 0) {
            quiz_add_quiz_question($existingquestion->id, $quiz, $addonpage);
            $number -= 1;
        }
    }

    if ($number <= 0) {
        return;
    }

    // More random questions are needed, create them.
    for ($i = 0; $i < $number; $i += 1) {
        $form = new stdClass();
        $form->questiontext = array('text' => $includesubcategories, 'format' => 0);
        $form->category = $category->id . ',' . $category->contextid;
        $form->defaultmark = 1;
        $form->hidden = 1;
        $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed).
        $question = new stdClass();
        $question->qtype = 'random';
        $question = question_bank::get_qtype('random')->save_question($question, $form);
        if (!isset($question->id)) {
            print_error('cannotinsertrandomquestion', 'quiz');
        }
        quiz_add_quiz_question($question->id, $quiz, $addonpage);
    }
}
Example #19
0
function restore_question_category($category, $restore)
{
    $status = true;
    //Skip empty categories (some backups can contain them)
    if (!empty($category->id)) {
        //Get record from backup_ids
        $data = backup_getid($restore->backup_unique_code, "question_categories", $category->id);
        if ($data) {
            //Now get completed xmlized object
            $info = $data->info;
            //traverse_xmlize($info);                                                                     //Debug
            //print_object ($GLOBALS['traverse_array']);                                                  //Debug
            //$GLOBALS['traverse_array']="";                                                              //Debug
            //Now, build the question_categories record structure
            $question_cat = new stdClass();
            $question_cat->name = backup_todb($info['QUESTION_CATEGORY']['#']['NAME']['0']['#']);
            $question_cat->info = backup_todb($info['QUESTION_CATEGORY']['#']['INFO']['0']['#']);
            $question_cat->stamp = backup_todb($info['QUESTION_CATEGORY']['#']['STAMP']['0']['#']);
            //parent is fixed after all categories are restored and we know all the new ids.
            $question_cat->parent = backup_todb($info['QUESTION_CATEGORY']['#']['PARENT']['0']['#']);
            $question_cat->sortorder = backup_todb($info['QUESTION_CATEGORY']['#']['SORTORDER']['0']['#']);
            if (!$question_cat->stamp) {
                $question_cat->stamp = make_unique_id_code();
            }
            if (isset($info['QUESTION_CATEGORY']['#']['PUBLISH'])) {
                $course = $restore->course_id;
                $publish = backup_todb($info['QUESTION_CATEGORY']['#']['PUBLISH']['0']['#']);
                if ($publish) {
                    $tocontext = get_context_instance(CONTEXT_SYSTEM);
                } else {
                    $tocontext = get_context_instance(CONTEXT_COURSE, $course);
                }
            } else {
                if (!($tocontext = restore_question_get_best_category_context($restore, $info['QUESTION_CATEGORY']['#']['CONTEXT']['0']['#']))) {
                    return $status;
                    // context doesn't exist - a module has not been restored
                }
            }
            $question_cat->contextid = $tocontext->id;
            //does cat exist ?? if it does we check if the cat and questions already exist whether we have
            //add permission or not if we have no permission to add questions to SYSTEM or COURSECAT context
            //AND the question does not already exist then we create questions in COURSE context.
            if (!($fcat = get_record('question_categories', 'contextid', $question_cat->contextid, 'stamp', $question_cat->stamp))) {
                //no preexisting cat
                if (($tocontext->contextlevel == CONTEXT_SYSTEM || $tocontext->contextlevel == CONTEXT_COURSECAT) && !has_capability('moodle/question:add', $tocontext)) {
                    //no preexisting cat and no permission to create questions here
                    //must restore to course.
                    $tocontext = get_context_instance(CONTEXT_COURSE, $restore->course_id);
                }
                $question_cat->contextid = $tocontext->id;
                if (!($fcat = get_record('question_categories', 'contextid', $question_cat->contextid, 'stamp', $question_cat->stamp))) {
                    $question_cat->id = insert_record("question_categories", $question_cat);
                } else {
                    $question_cat = $fcat;
                }
                //we'll be restoring all questions here.
                backup_putid($restore->backup_unique_code, "question_categories", $category->id, $question_cat->id);
            } else {
                $question_cat = $fcat;
                //we found an existing best category
                //but later if context is above course need to check if there are questions need creating in category
                //if we do need to create questions and permissions don't allow it create new category in course
            }
            //Do some output
            if (!defined('RESTORE_SILENTLY')) {
                echo "<li>" . get_string('category', 'quiz') . " \"" . $question_cat->name . "\"<br />";
            }
            backup_flush(300);
            //start with questions
            if ($question_cat->id) {
                //We have the newid, update backup_ids
                //Now restore question
                $status = restore_questions($category->id, $question_cat, $info, $restore);
            } else {
                $status = false;
            }
            if (!defined('RESTORE_SILENTLY')) {
                echo '</li>';
            }
        } else {
            echo 'Could not get backup info for question category' . $category->id;
        }
    }
    return $status;
}
/**
* Gets the default category in the most specific context.
* If no categories exist yet then default ones are created in all contexts.
*
* @param array $contexts  The context objects for this context and all parent contexts.
* @return object The default category - the category in the course context
*/
function question_make_default_categories($contexts)
{
    static $preferredlevels = array(CONTEXT_COURSE => 4, CONTEXT_MODULE => 3, CONTEXT_COURSECAT => 2, CONTEXT_SYSTEM => 1);
    $toreturn = null;
    $preferredness = 0;
    // If it already exists, just return it.
    foreach ($contexts as $key => $context) {
        if (!($categoryrs = get_recordset_select("question_categories", "contextid = '{$context->id}'", 'sortorder, name', '*', '', 1))) {
            error('error getting category record');
        } else {
            if (!($category = rs_fetch_record($categoryrs))) {
                // Otherwise, we need to make one
                $category = new stdClass();
                $contextname = print_context_name($context, false, true);
                $category->name = addslashes(get_string('defaultfor', 'question', $contextname));
                $category->info = addslashes(get_string('defaultinfofor', 'question', $contextname));
                $category->contextid = $context->id;
                $category->parent = 0;
                $category->sortorder = 999;
                // By default, all categories get this number, and are sorted alphabetically.
                $category->stamp = make_unique_id_code();
                if (!($category->id = insert_record('question_categories', $category))) {
                    error('Error creating a default category for context ' . print_context_name($context));
                }
            }
        }
        if ($preferredlevels[$context->contextlevel] > $preferredness && has_any_capability(array('moodle/question:usemine', 'moodle/question:useall'), $context)) {
            $toreturn = $category;
            $preferredness = $preferredlevels[$context->contextlevel];
        }
    }
    if (!is_null($toreturn)) {
        $toreturn = clone $toreturn;
    }
    return $toreturn;
}
Example #21
0
    /**
     * Creates a new category with given params
     */
    public function add_category($newparent, $newcategory, $newinfo, $return = false) {
        global $DB;
        if (empty($newcategory)) {
            print_error('categorynamecantbeblank', 'question');
        }
        list($parentid, $contextid) = explode(',', $newparent);
        //moodle_form makes sure select element output is legal no need for further cleaning
        require_capability('moodle/question:managecategory', context::instance_by_id($contextid));

        if ($parentid) {
            if(!($DB->get_field('question_categories', 'contextid', array('id' => $parentid)) == $contextid)) {
                print_error('cannotinsertquestioncatecontext', 'question', '', array('cat'=>$newcategory, 'ctx'=>$contextid));
            }
        }

        $cat = new stdClass();
        $cat->parent = $parentid;
        $cat->contextid = $contextid;
        $cat->name = $newcategory;
        $cat->info = $newinfo;
        $cat->sortorder = 999;
        $cat->stamp = make_unique_id_code();
        $categoryid = $DB->insert_record("question_categories", $cat);
        if ($return) {
            return $categoryid;
        } else {
            redirect($this->pageurl);//always redirect after successful action
        }
    }
Example #22
0
 /**
  * find and/or create the category described by a delimited list
  * e.g. $course$/tom/dick/harry or tom/dick/harry
  *
  * removes any context string no matter whether $getcontext is set
  * but if $getcontext is set then ignore the context and use selected category context.
  *
  * @param string catpath delimited category path
  * @param string delimiter path delimiting character
  * @param int courseid course to search for categories
  * @return mixed category object or null if fails
  */
 function create_category_path($catpath, $delimiter = '/')
 {
     $catpath = clean_param($catpath, PARAM_PATH);
     $catnames = explode($delimiter, $catpath);
     $parent = 0;
     $category = null;
     // check for context id in path, it might not be there in pre 1.9 exports
     $matchcount = preg_match('/^\\$([a-z]+)\\$$/', $catnames[0], $matches);
     if ($matchcount == 1) {
         $contextid = $this->translator->string_to_context($matches[1]);
         array_shift($catnames);
     } else {
         $contextid = FALSE;
     }
     if ($this->contextfromfile && $contextid !== FALSE) {
         $context = get_context_instance_by_id($contextid);
         require_capability('moodle/question:add', $context);
     } else {
         $context = get_context_instance_by_id($this->category->contextid);
     }
     foreach ($catnames as $catname) {
         if ($category = get_record('question_categories', 'name', $catname, 'contextid', $context->id, 'parent', $parent)) {
             $parent = $category->id;
         } else {
             require_capability('moodle/question:managecategory', $context);
             // create the new category
             $category = new object();
             $category->contextid = $context->id;
             $category->name = $catname;
             $category->info = '';
             $category->parent = $parent;
             $category->sortorder = 999;
             $category->stamp = make_unique_id_code();
             if (!($id = insert_record('question_categories', $category))) {
                 error("cannot create new category - {$catname}");
             }
             $category->id = $id;
             $parent = $id;
         }
     }
     return $category;
 }
Example #23
0
    /**
     * Saves (creates or updates) a question.
     *
     * Given some question info and some data about the answers
     * this function parses, organises and saves the question
     * It is used by {@link question.php} when saving new data from
     * a form, and also by {@link import.php} when importing questions
     * This function in turn calls {@link save_question_options}
     * to save question-type specific data.
     *
     * Whether we are saving a new question or updating an existing one can be
     * determined by testing !empty($question->id). If it is not empty, we are updating.
     *
     * The question will be saved in category $form->category.
     *
     * @param object $question the question object which should be updated. For a
     *      new question will be mostly empty.
     * @param object $form the object containing the information to save, as if
     *      from the question editing form.
     * @param object $course not really used any more.
     * @return object On success, return the new question object. On failure,
     *       return an object as follows. If the error object has an errors field,
     *       display that as an error message. Otherwise, the editing form will be
     *       redisplayed with validation errors, from validation_errors field, which
     *       is itself an object, shown next to the form fields. (I don't think this
     *       is accurate any more.)
     */
    public function save_question($question, $form) {
        global $USER, $DB, $OUTPUT;

        list($question->category) = explode(',', $form->category);
        $context = $this->get_context_by_category_id($question->category);

        // This default implementation is suitable for most
        // question types.

        // First, save the basic question itself.
        $question->name = trim($form->name);
        $question->parent = isset($form->parent) ? $form->parent : 0;
        $question->length = $this->actual_number_of_questions($question);
        $question->penalty = isset($form->penalty) ? $form->penalty : 0;

        if (empty($form->questiontext['text'])) {
            $question->questiontext = '';
        } else {
            $question->questiontext = trim($form->questiontext['text']);
        }
        $question->questiontextformat = !empty($form->questiontext['format']) ?
                $form->questiontext['format'] : 0;

        if (empty($form->generalfeedback['text'])) {
            $question->generalfeedback = '';
        } else {
            $question->generalfeedback = trim($form->generalfeedback['text']);
        }
        $question->generalfeedbackformat = !empty($form->generalfeedback['format']) ?
                $form->generalfeedback['format'] : 0;

        if (empty($question->name)) {
            $question->name = shorten_text(strip_tags($form->questiontext['text']), 15);
            if (empty($question->name)) {
                $question->name = '-';
            }
        }

        if ($question->penalty > 1 or $question->penalty < 0) {
            $question->errors['penalty'] = get_string('invalidpenalty', 'question');
        }

        if (isset($form->defaultmark)) {
            $question->defaultmark = $form->defaultmark;
        }

        // If the question is new, create it.
        if (empty($question->id)) {
            // Set the unique code.
            $question->stamp = make_unique_id_code();
            $question->createdby = $USER->id;
            $question->timecreated = time();
            $question->id = $DB->insert_record('question', $question);
        }

        // Now, whether we are updating a existing question, or creating a new
        // one, we have to do the files processing and update the record.
        // Question already exists, update.
        $question->modifiedby = $USER->id;
        $question->timemodified = time();

        if (!empty($question->questiontext) && !empty($form->questiontext['itemid'])) {
            $question->questiontext = file_save_draft_area_files($form->questiontext['itemid'],
                    $context->id, 'question', 'questiontext', (int)$question->id,
                    $this->fileoptions, $question->questiontext);
        }
        if (!empty($question->generalfeedback) && !empty($form->generalfeedback['itemid'])) {
            $question->generalfeedback = file_save_draft_area_files(
                    $form->generalfeedback['itemid'], $context->id,
                    'question', 'generalfeedback', (int)$question->id,
                    $this->fileoptions, $question->generalfeedback);
        }
        $DB->update_record('question', $question);

        // Now to save all the answers and type-specific options.
        $form->id = $question->id;
        $form->qtype = $question->qtype;
        $form->category = $question->category;
        $form->questiontext = $question->questiontext;
        $form->questiontextformat = $question->questiontextformat;
        // Current context.
        $form->context = $context;

        $result = $this->save_question_options($form);

        if (!empty($result->error)) {
            print_error($result->error);
        }

        if (!empty($result->notice)) {
            notice($result->notice, "question.php?id=$question->id");
        }

        if (!empty($result->noticeyesno)) {
            throw new coding_exception(
                    '$result->noticeyesno no longer supported in save_question.');
        }

        // Give the question a unique version stamp determined by question_hash().
        $DB->set_field('question', 'version', question_hash($question),
                array('id' => $question->id));

        return $question;
    }
function quiz_restore_pre15_multianswer($old_question_id, $new_question_id, $info, $restore)
{
    global $CFG;
    $status = true;
    //We need some question fields here so we get the full record from DB
    $parentquestion = get_record('question', 'id', $new_question_id);
    //We need to store all the positions with their created questions
    //to be able to calculate the sequence field
    $createdquestions = array();
    //Under 1.5, every multianswer record becomes a question itself
    //with its parent set to the cloze question. And there is only
    //ONE multianswer record with the sequence of questions used.
    //Get the multianswers array
    $multianswers_array = $info['#']['MULTIANSWERS']['0']['#']['MULTIANSWER'];
    //Iterate over multianswers_array
    for ($i = 0; $i < sizeof($multianswers_array); $i++) {
        $mul_info = $multianswers_array[$i];
        //traverse_xmlize($mul_info);                                                                 //Debug
        //print_object ($GLOBALS['traverse_array']);                                                  //Debug
        //$GLOBALS['traverse_array']="";                                                              //Debug
        //We need this later
        $oldid = backup_todb($mul_info['#']['ID']['0']['#']);
        //Now, build the question_multianswer record structure
        $multianswer->question = $new_question_id;
        $multianswer->answers = backup_todb($mul_info['#']['ANSWERS']['0']['#']);
        $multianswer->positionkey = backup_todb($mul_info['#']['POSITIONKEY']['0']['#']);
        $multianswer->answertype = backup_todb($mul_info['#']['ANSWERTYPE']['0']['#']);
        $multianswer->norm = backup_todb($mul_info['#']['NORM']['0']['#']);
        //Saving multianswer and positionkey to use them later restoring states
        backup_putid($restore->backup_unique_code, 'multianswer-pos', $oldid, $multianswer->positionkey);
        //We have to recode all the answers to their new ids
        $ansarr = explode(",", $multianswer->answers);
        foreach ($ansarr as $key => $value) {
            //Get the answer from backup_ids
            $answer = backup_getid($restore->backup_unique_code, 'question_answers', $value);
            $ansarr[$key] = $answer->new_id;
        }
        $multianswer->answers = implode(",", $ansarr);
        //Build the new question structure
        $question = new object();
        $question->category = $parentquestion->category;
        $question->parent = $parentquestion->id;
        $question->name = $parentquestion->name;
        $question->questiontextformat = $parentquestion->questiontextformat;
        $question->defaultgrade = $multianswer->norm;
        $question->penalty = $parentquestion->penalty;
        $question->qtype = $multianswer->answertype;
        $question->version = $parentquestion->version;
        $question->hidden = $parentquestion->hidden;
        $question->length = 0;
        $question->questiontext = '';
        $question->stamp = make_unique_id_code();
        //Save the new question to DB
        $newid = insert_record('question', $question);
        if ($newid) {
            $createdquestions[$multianswer->positionkey] = $newid;
        }
        //Do some output
        if (($i + 1) % 50 == 0) {
            if (!defined('RESTORE_SILENTLY')) {
                echo ".";
                if (($i + 1) % 1000 == 0) {
                    echo "<br />";
                }
            }
            backup_flush(300);
        }
        //Remap question_answers records from the original multianswer question
        //to their newly created question
        if ($newid) {
            $answersdb = get_records_list('question_answers', 'id', $multianswer->answers);
            foreach ($answersdb as $answerdb) {
                set_field('question_answers', 'question', $newid, 'id', $answerdb->id);
            }
        }
        //If we have created the question record, now, depending of the
        //answertype, delegate the restore to every qtype function
        if ($newid) {
            if ($multianswer->answertype == "1") {
                $status = quiz_restore_pre15_shortanswer($old_question_id, $newid, $mul_info, $restore, $multianswer->answers);
            } else {
                if ($multianswer->answertype == "3") {
                    $status = quiz_restore_pre15_multichoice($old_question_id, $newid, $mul_info, $restore, $multianswer->answers);
                } else {
                    if ($multianswer->answertype == "8") {
                        $status = quiz_restore_pre15_numerical($old_question_id, $newid, $mul_info, $restore, $multianswer->answers);
                    }
                }
            }
        } else {
            $status = false;
        }
    }
    //Everything is created, just going to create the multianswer record
    if ($status) {
        ksort($createdquestions);
        $multianswerdb = new object();
        $multianswerdb->question = $parentquestion->id;
        $multianswerdb->sequence = implode(",", $createdquestions);
        $mid = insert_record('question_multianswer', $multianswerdb);
        if (!$mid) {
            $status = false;
        }
    }
    return $status;
}
Example #25
0
 /**
  * Saves (creates or updates) a question.
  *
  * Given some question info and some data about the answers
  * this function parses, organises and saves the question
  * It is used by {@link question.php} when saving new data from
  * a form, and also by {@link import.php} when importing questions
  * This function in turn calls {@link save_question_options}
  * to save question-type specific data.
  *
  * Whether we are saving a new question or updating an existing one can be
  * determined by testing !empty($question->id). If it is not empty, we are updating.
  *
  * The question will be saved in category $form->category.
  *
  * @param object $question the question object which should be updated. For a new question will be mostly empty.
  * @param object $form the object containing the information to save, as if from the question editing form.
  * @param object $course not really used any more.
  * @return object On success, return the new question object. On failure,
  *       return an object as follows. If the error object has an errors field,
  *       display that as an error message. Otherwise, the editing form will be
  *       redisplayed with validation errors, from validation_errors field, which
  *       is itself an object, shown next to the form fields. (I don't think this is accurate any more.)
  */
 function save_question($question, $form, $course)
 {
     global $USER;
     // This default implementation is suitable for most
     // question types.
     // First, save the basic question itself
     $question->name = trim($form->name);
     $question->questiontext = trim($form->questiontext);
     $question->questiontextformat = $form->questiontextformat;
     $question->parent = isset($form->parent) ? $form->parent : 0;
     $question->length = $this->actual_number_of_questions($question);
     $question->penalty = isset($form->penalty) ? $form->penalty : 0;
     if (empty($form->image)) {
         $question->image = '';
     } else {
         $question->image = $form->image;
     }
     if (empty($form->generalfeedback)) {
         $question->generalfeedback = '';
     } else {
         $question->generalfeedback = trim($form->generalfeedback);
     }
     if (empty($question->name)) {
         $question->name = shorten_text(strip_tags($question->questiontext), 15);
         if (empty($question->name)) {
             $question->name = '-';
         }
     }
     if ($question->penalty > 1 or $question->penalty < 0) {
         $question->errors['penalty'] = get_string('invalidpenalty', 'quiz');
     }
     if (isset($form->defaultgrade)) {
         $question->defaultgrade = $form->defaultgrade;
     }
     list($question->category) = explode(',', $form->category);
     if (!empty($question->id)) {
         /// Question already exists, update.
         $question->modifiedby = $USER->id;
         $question->timemodified = time();
         if (!update_record('question', $question)) {
             error('Could not update question!');
         }
     } else {
         /// New question.
         // Set the unique code
         $question->stamp = make_unique_id_code();
         $question->createdby = $USER->id;
         $question->modifiedby = $USER->id;
         $question->timecreated = time();
         $question->timemodified = time();
         if (!($question->id = insert_record('question', $question))) {
             error('Could not insert new question!');
         }
     }
     // Now to save all the answers and type-specific options
     $form->id = $question->id;
     $form->qtype = $question->qtype;
     $form->category = $question->category;
     $form->questiontext = $question->questiontext;
     $result = $this->save_question_options($form);
     if (!empty($result->error)) {
         error($result->error);
     }
     if (!empty($result->notice)) {
         notice($result->notice, "question.php?id={$question->id}");
     }
     if (!empty($result->noticeyesno)) {
         notice_yesno($result->noticeyesno, "question.php?id={$question->id}&amp;courseid={$course->id}", "edit.php?courseid={$course->id}");
         print_footer($course);
         exit;
     }
     // Give the question a unique version stamp determined by question_hash()
     if (!set_field('question', 'version', question_hash($question), 'id', $question->id)) {
         error('Could not update question version field');
     }
     return $question;
 }
Example #26
0
function quiz_upgrade($oldversion)
{
    // This function does anything necessary to upgrade
    // older versions to match current functionality
    global $CFG, $QTYPES, $db;
    $success = true;
    require_once "{$CFG->dirroot}/mod/quiz/locallib.php";
    if ($success && $oldversion < 2002101800) {
        $success = $success && execute_sql(" ALTER TABLE `quiz_attempts` " . " ADD `timestart` INT(10) UNSIGNED DEFAULT '0' NOT NULL AFTER `sumgrades` , " . " ADD `timefinish` INT(10) UNSIGNED DEFAULT '0' NOT NULL AFTER `timestart` ");
        $success = $success && execute_sql(" UPDATE `quiz_attempts` SET timestart = timemodified ");
        $success = $success && execute_sql(" UPDATE `quiz_attempts` SET timefinish = timemodified ");
    }
    if ($success && $oldversion < 2002102101) {
        $success = $success && execute_sql(" DELETE FROM log_display WHERE module = 'quiz' ");
        $success = $success && execute_sql(" INSERT INTO log_display (module, action, mtable, field) VALUES ('quiz', 'view', 'quiz', 'name') ");
        $success = $success && execute_sql(" INSERT INTO log_display (module, action, mtable, field) VALUES ('quiz', 'report', 'quiz', 'name') ");
        $success = $success && execute_sql(" INSERT INTO log_display (module, action, mtable, field) VALUES ('quiz', 'attempt', 'quiz', 'name') ");
        $success = $success && execute_sql(" INSERT INTO log_display (module, action, mtable, field) VALUES ('quiz', 'submit', 'quiz', 'name') ");
    }
    if ($success && $oldversion < 2002102600) {
        $success = $success && execute_sql(" ALTER TABLE `quiz_answers` CHANGE `feedback` `feedback` TEXT NOT NULL ");
    }
    if ($success && $oldversion < 2002122300) {
        $success = $success && execute_sql("ALTER TABLE `quiz_grades` CHANGE `user` `userid` INT(10) UNSIGNED DEFAULT '0' NOT NULL ");
        $success = $success && execute_sql("ALTER TABLE `quiz_attempts` CHANGE `user` `userid` INT(10) UNSIGNED DEFAULT '0' NOT NULL ");
    }
    // prefixes required from here on, or use table_column()
    if ($success && $oldversion < 2003010100) {
        $success = $success && execute_sql(" ALTER TABLE {$CFG->prefix}quiz ADD review TINYINT(4) UNSIGNED DEFAULT '0' NOT NULL AFTER `grademethod` ");
    }
    if ($success && $oldversion < 2003010301) {
        $success = $success && table_column("quiz_truefalse", "true", "trueanswer", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", "");
        $success = $success && table_column("quiz_truefalse", "false", "falseanswer", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", "");
        $success = $success && table_column("quiz_questions", "type", "qtype", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", "");
    }
    if ($success && $oldversion < 2003022303) {
        $success = $success && modify_database("", "CREATE TABLE `prefix_quiz_randommatch` (\n                             `id` int(10) unsigned NOT NULL auto_increment,\n                             `question` int(10) unsigned NOT NULL default '0',\n                             `choose` INT UNSIGNED DEFAULT '4' NOT NULL,\n                             PRIMARY KEY ( `id` )\n                          );");
    }
    if ($success && $oldversion < 2003030303) {
        $success = $success && table_column("quiz_questions", "", "defaultgrade", "INTEGER", "6", "UNSIGNED", "1", "NOT NULL", "image");
    }
    if ($success && $oldversion < 2003032601) {
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_answers` ADD INDEX(question) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_attempts` ADD INDEX(quiz) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_attempts` ADD INDEX(userid) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_grades` ADD INDEX(quiz) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_grades` ADD INDEX(userid) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_question_grades` ADD INDEX(quiz) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_question_grades` ADD INDEX(question) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_randommatch` ADD INDEX(question) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_responses` ADD INDEX(attempt) ");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz_responses` ADD INDEX(question) ");
    }
    if ($success && $oldversion < 2003033100) {
        $success = $success && modify_database("", "ALTER TABLE prefix_quiz_randommatch RENAME prefix_quiz_randomsamatch ");
        $success = $success && modify_database("", "CREATE TABLE `prefix_quiz_match` (\n                             `id` int(10) unsigned NOT NULL auto_increment,\n                             `question` int(10) unsigned NOT NULL default '0',\n                             `subquestions` varchar(255) NOT NULL default '',\n                             PRIMARY KEY  (`id`),\n                             KEY `question` (`question`)\n                           );");
        $success = $success && modify_database("", "CREATE TABLE `prefix_quiz_match_sub` (\n                             `id` int(10) unsigned NOT NULL auto_increment,\n                             `question` int(10) unsigned NOT NULL default '0',\n                             `questiontext` text NOT NULL,\n                             `answertext` varchar(255) NOT NULL default '',\n                             PRIMARY KEY  (`id`),\n                             KEY `question` (`question`)\n                           );");
    }
    if ($success && $oldversion < 2003040901) {
        $success = $success && table_column("quiz", "", "shufflequestions", "INTEGER", "4", "UNSIGNED", "0", "NOT NULL", "review");
        $success = $success && table_column("quiz", "", "shuffleanswers", "INTEGER", "4", "UNSIGNED", "0", "NOT NULL", "shufflequestions");
    }
    if ($success && $oldversion < 2003071001) {
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_numerical` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                               `question` int(10) unsigned NOT NULL default '0',\n                               `answer` int(10) unsigned NOT NULL default '0',\n                               `min` varchar(255) NOT NULL default '',\n                               `max` varchar(255) NOT NULL default '',\n                               PRIMARY KEY  (`id`),\n                               KEY `answer` (`answer`)\n                             ) TYPE=MyISAM COMMENT='Options for numerical questions'; ");
    }
    if ($success && $oldversion < 2003072400) {
        $success = $success && execute_sql(" INSERT INTO {$CFG->prefix}log_display (module, action, mtable, field) VALUES ('quiz', 'review', 'quiz', 'name') ");
    }
    if ($success && $oldversion < 2003072901) {
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_multianswers` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                                `question` int(10) unsigned NOT NULL default '0',\n                                `answers` varchar(255) NOT NULL default '',\n                                `positionkey` varchar(255) NOT NULL default '',\n                                `answertype` smallint(6) NOT NULL default '0',\n                                `norm` int(10) unsigned NOT NULL default '1',\n                                PRIMARY KEY  (`id`),\n                                KEY `question` (`question`)\n                              ) TYPE=MyISAM COMMENT='Options for multianswer questions'; ");
    }
    if ($success && $oldversion < 2003080301) {
        $success = $success && execute_sql(" ALTER TABLE {$CFG->prefix}quiz ADD eachattemptbuildsonthelast TINYINT(4) DEFAULT '0' NOT NULL AFTER `attempts` ");
    }
    if ($success && $oldversion < 2003080400) {
        $success = $success && table_column("quiz", "eachattemptbuildsonthelast", "attemptonlast", "TINYINT", "4", "UNSIGNED", "0", "NOT NULL", "");
    }
    if ($success && $oldversion < 2003082300) {
        $success = $success && table_column("quiz_questions", "", "stamp", "varchar", "255", "", "", "not null", "qtype");
    }
    if ($success && $oldversion < 2003082301) {
        $success = $success && table_column("quiz_questions", "stamp", "stamp", "varchar", "255", "", "", "not null");
        $success = $success && table_column("quiz_questions", "", "version", "integer", "10", "", "1", "not null", "stamp");
        if ($questions = get_records("quiz_questions")) {
            foreach ($questions as $question) {
                $stamp = make_unique_id_code();
                if (!($success = $success && set_field("quiz_questions", "stamp", $stamp, "id", $question->id))) {
                    notify("Error while adding stamp to question id = {$question->id}");
                    break;
                }
            }
        }
    }
    if ($success && $oldversion < 2003082700) {
        $success = $success && table_column("quiz_categories", "", "stamp", "varchar", "255", "", "", "not null");
        if ($categories = get_records("quiz_categories")) {
            foreach ($categories as $category) {
                $stamp = make_unique_id_code();
                if (!($success = $success && set_field("quiz_categories", "stamp", $stamp, "id", $category->id))) {
                    notify("Error while adding stamp to category id = {$category->id}");
                    break;
                }
            }
        }
    }
    if ($success && $oldversion < 2003111100) {
        $duplicates = get_records_sql("SELECT stamp as id,count(*) as cuenta\n                                       FROM {$CFG->prefix}quiz_questions\n                                       GROUP BY stamp\n                                       HAVING count(*)>1");
        if ($duplicates) {
            notify("You have some quiz questions with duplicate stamps IDs.  Cleaning these up.");
            foreach ($duplicates as $duplicate) {
                $questions = get_records("quiz_questions", "stamp", $duplicate->id);
                $add = 1;
                foreach ($questions as $question) {
                    echo "Changing question id {$question->id} stamp to " . $duplicate->id . $add . "<br />";
                    $success = $success && set_field("quiz_questions", "stamp", $duplicate->id . $add, "id", $question->id);
                    $add++;
                }
            }
        } else {
            notify("Checked your quiz questions for stamp duplication errors, but no problems were found.", "green");
        }
    }
    if ($success && $oldversion < 2004021300) {
        $success = $success && table_column("quiz_questions", "", "questiontextformat", "integer", "2", "", "0", "not null", "questiontext");
    }
    if ($success && $oldversion < 2004021900) {
        $success = $success && modify_database("", "INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('quiz', 'add', 'quiz', 'name');");
        $success = $success && modify_database("", "INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('quiz', 'update', 'quiz', 'name');");
    }
    if ($success && $oldversion < 2004051700) {
        include_once "{$CFG->dirroot}/mod/quiz/lib.php";
        $success = $success && quiz_refresh_events();
    }
    if ($success && $oldversion < 2004060200) {
        $success = $success && execute_sql(" ALTER TABLE {$CFG->prefix}quiz ADD timelimit INT(2) UNSIGNED DEFAULT '0' NOT NULL ");
    }
    if ($success && $oldversion < 2004070700) {
        $success = $success && table_column("quiz", "", "password", "varchar", "255", "", "", "not null", "");
        $success = $success && table_column("quiz", "", "subnet", "varchar", "255", "", "", "not null", "");
    }
    if ($success && $oldversion < 2004073001) {
        // Six new tables:
        // One table for handling units for numerical questions
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_numerical_units` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                               `question` int(10) unsigned NOT NULL default '0',\n                               `multiplier` decimal(40,20) NOT NULL default '1.00000000000000000000',\n                               `unit` varchar(50) NOT NULL default '',\n                               PRIMARY KEY  (`id`)\n                ) TYPE=MyISAM COMMENT='Optional unit options for numerical questions'; ");
        // Four tables for handling distribution and storage of
        // individual data for dataset dependent question types
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_attemptonlast_datasets` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                               `category` int(10) unsigned NOT NULL default '0',\n                               `userid` int(10) unsigned NOT NULL default '0',\n                               `datasetnumber` int(10) unsigned NOT NULL default '0',\n                               PRIMARY KEY  (`id`),\n                               UNIQUE KEY `category` (`category`,`userid`)\n            ) TYPE=MyISAM COMMENT='Dataset number for attemptonlast attempts per user'; ");
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_dataset_definitions` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                               `category` int(10) unsigned NOT NULL default '0',\n                               `name` varchar(255) NOT NULL default '',\n                               `type` int(10) NOT NULL default '0',\n                               `options` varchar(255) NOT NULL default '',\n                               `itemcount` int(10) unsigned NOT NULL default '0',\n                               PRIMARY KEY  (`id`)\n            ) TYPE=MyISAM COMMENT='Organises and stores properties for dataset items'; ");
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_dataset_items` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                               `definition` int(10) unsigned NOT NULL default '0',\n                               `number` int(10) unsigned NOT NULL default '0',\n                               `value` varchar(255) NOT NULL default '',\n                               PRIMARY KEY  (`id`),\n                               KEY `definition` (`definition`)\n                             ) TYPE=MyISAM COMMENT='Individual dataset items'; ");
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_question_datasets` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                               `question` int(10) unsigned NOT NULL default '0',\n                               `datasetdefinition` int(10) unsigned NOT NULL default '0',\n                               PRIMARY KEY  (`id`),\n                               KEY `question` (`question`,`datasetdefinition`)\n            ) TYPE=MyISAM COMMENT='Many-many relation between questions and dataset definitions'; ");
        // One table for new question type calculated
        //  - the first dataset dependent question type
        $success = $success && modify_database("", " CREATE TABLE `prefix_quiz_calculated` (\n                               `id` int(10) unsigned NOT NULL auto_increment,\n                               `question` int(10) unsigned NOT NULL default '0',\n                               `answer` int(10) unsigned NOT NULL default '0',\n                               `tolerance` varchar(20) NOT NULL default '0.0',\n                               `tolerancetype` int(10) NOT NULL default '1',\n                               `correctanswerlength` int(10) NOT NULL default '2',\n                               PRIMARY KEY  (`id`),\n                               KEY `question` (`question`)\n                ) TYPE=MyISAM COMMENT='Options for questions of type calculated'; ");
    }
    if ($success && $oldversion < 2004111400) {
        $success = $success && table_column("quiz_responses", "answer", "answer", "text", "", "", "", "not null");
    }
    if ($success && $oldversion < 2004111700) {
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz DROP INDEX course;", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_calculated DROP INDEX answer;", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_categories DROP INDEX course;", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_dataset_definitions DROP INDEX category;", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_numerical DROP INDEX question;", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_numerical_units DROP INDEX question;", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_questions DROP INDEX category;", false);
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz ADD INDEX course (course);');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_calculated ADD INDEX answer (answer);');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_categories ADD INDEX course (course);');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_dataset_definitions ADD INDEX category (category);');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_numerical ADD INDEX question (question);');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_numerical_units ADD INDEX question (question);');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_questions ADD INDEX category (category);');
    }
    if ($success && $oldversion < 2004120501) {
        $success = $success && table_column("quiz_calculated", "", "correctanswerformat", "integer", "10", "", "2", "not null", "correctanswerlength");
    }
    if ($success && $oldversion < 2004121400) {
        // New field to determine popup window behaviour
        $success = $success && table_column("quiz", "", "popup", "integer", "4", "", "0", "not null", "subnet");
    }
    if ($success && $oldversion < 2005010201) {
        $success = $success && table_column('quiz_categories', '', 'parent');
        $success = $success && table_column('quiz_categories', '', 'sortorder', 'integer', '10', '', '999');
    }
    if ($success && $oldversion < 2005010300) {
        $success = $success && table_column("quiz", "", "questionsperpage", "integer", "10", "", "0", "not null", "review");
    }
    if ($success && $oldversion < 2005012700) {
        $success = $success && table_column('quiz_grades', 'grade', 'grade', 'real', 2, '');
    }
    if ($success && $oldversion < 2005021400) {
        $success = $success && table_column("quiz", "", "decimalpoints", "integer", "4", "", "2", "not null", "grademethod");
    }
    if ($success && $oldversion < 2005022800) {
        $success = $success && table_column('quiz_questions', '', 'hidden', 'integer', '1', 'unsigned', '0', 'not null', 'version');
        $success = $success && table_column('quiz_responses', '', 'originalquestion', 'integer', '10', 'unsigned', '0', 'not null', 'question');
        $success = $success && modify_database('', "CREATE TABLE `prefix_quiz_question_version` (\n                              `id` int(10) unsigned NOT NULL auto_increment,\n                              `quiz` int(10) unsigned NOT NULL default '0',\n                              `oldquestion` int(10) unsigned NOT NULL default '0',\n                              `newquestion` int(10) unsigned NOT NULL default '0',\n                              `userid` int(10) unsigned NOT NULL default '0',\n                              `timestamp` int(10) unsigned NOT NULL default '0',\n                              PRIMARY KEY  (`id`)\n                            ) TYPE=MyISAM COMMENT='The mapping between old and new versions of a question';");
    }
    if ($success && $oldversion < 2005032000) {
        $success = $success && execute_sql(" INSERT INTO {$CFG->prefix}log_display (module, action, mtable, field) VALUES ('quiz', 'editquestions', 'quiz', 'name') ");
    }
    if ($success && $oldversion < 2005032300) {
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_question_version RENAME prefix_quiz_question_versions;');
    }
    if ($success && $oldversion < 2005041200) {
        // replace wiki-like with markdown
        include_once "{$CFG->dirroot}/lib/wiki_to_markdown.php";
        $wtm = new WikiToMarkdown();
        $sql = "select course from {$CFG->prefix}quiz_categories c, {$CFG->prefix}quiz_questions q ";
        $sql .= "where c.id = q.category ";
        $sql .= "and q.id = ";
        $wtm->update('quiz_questions', 'questiontext', 'questiontextformat', $sql);
    }
    if ($success && $oldversion < 2005041304) {
        // make random questions hidden
        $success = $success && modify_database('', "UPDATE prefix_quiz_questions SET hidden = '1' WHERE qtype ='" . RANDOM . "';");
    }
    if ($success && $oldversion < 2005042002) {
        $success = $success && table_column('quiz_answers', 'answer', 'answer', 'text', '', '', '', 'not null', '');
    }
    if ($success && $oldversion < 2005042400) {
        // Changes to quiz table
        // The bits of the optionflags field will hold various option flags
        $success = $success && table_column('quiz', '', 'optionflags', 'integer', '10', 'unsigned', '0', 'not null', 'timeclose');
        // The penalty scheme
        $success = $success && table_column('quiz', '', 'penaltyscheme', 'integer', '4', 'unsigned', '0', 'not null', 'optionflags');
        // The review options are now all stored in the bits of the review field
        $success = $success && table_column('quiz', 'review', 'review', 'integer', 10, 'unsigned', 0, 'not null', '');
        /// Changes to quiz_attempts table
        // The preview flag marks teacher previews
        $success = $success && table_column('quiz_attempts', '', 'preview', 'tinyint', '2', 'unsigned', '0', 'not null', 'timemodified');
        // The layout is the list of questions with inserted page breaks.
        $success = $success && table_column('quiz_attempts', '', 'layout', 'text', '', '', '', 'not null', 'timemodified');
        // For old quiz attempts we will set this to the repaginated question list from $quiz->questions
        /// The following updates of field values require a loop through all quizzes
        // This is because earlier versions of mysql don't allow joins in UPDATE
        if ($quizzes = get_records('quiz')) {
            // turn reporting off temporarily to avoid one line output per set_field
            $olddebug = $db->debug;
            $db->debug = false;
            echo 'Now updating ' . count($quizzes) . ' quizzes';
            foreach ($quizzes as $quiz) {
                // repaginate
                if ($quiz->questionsperpage) {
                    $quiz->questions = quiz_repaginate($quiz->questions, $quiz->questionsperpage);
                    $success = $success && set_field('quiz', 'questions', $quiz->questions, 'id', $quiz->id);
                }
                $success = $success && set_field('quiz_attempts', 'layout', $quiz->questions, 'quiz', $quiz->id);
                // set preview flag
                if ($teachers = get_course_teachers($quiz->course)) {
                    $teacherids = implode(',', array_keys($teachers));
                    $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_attempts SET preview = 1 WHERE userid IN ({$teacherids})");
                }
                // set review flags in quiz table
                $review = QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_RESPONSES + QUIZ_REVIEW_SCORES;
                if ($quiz->feedback) {
                    $review += QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_FEEDBACK;
                }
                if ($quiz->correctanswers) {
                    $review += QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_ANSWERS;
                }
                if ($quiz->review & 1) {
                    $review += QUIZ_REVIEW_CLOSED;
                }
                if ($quiz->review & 2) {
                    $review += QUIZ_REVIEW_OPEN;
                }
                $success = $success && set_field('quiz', 'review', $review, 'id', $quiz->id);
            }
            $db->debug = $olddebug;
        }
        // We can now drop the fields whose data has been moved to the review field
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz` DROP feedback");
        $success = $success && execute_sql(" ALTER TABLE `{$CFG->prefix}quiz` DROP correctanswers");
        /// Renaming tables
        // rename the quiz_question_grades table to quiz_question_instances
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_question_grades RENAME prefix_quiz_question_instances;');
        // rename the quiz_responses table quiz_states
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_responses RENAME prefix_quiz_states;');
        /// add columns to quiz_states table
        // The sequence number of the state.
        $success = $success && table_column('quiz_states', '', 'seq_number', 'integer', '6', 'unsigned', '0', 'not null', 'originalquestion');
        // For existing states we leave this at 0 because in the old quiz code there was only one response allowed
        // The time the state was created.
        $success = $success && table_column('quiz_states', '', 'timestamp', 'integer', '10', 'unsigned', '0', 'not null', 'answer');
        // For existing states we will below set this to the timemodified field of the attempt
        // The type of event that led to the creation of the state
        $success = $success && table_column('quiz_states', '', 'event', 'integer', '4', 'unsigned', '0', 'not null', 'timestamp');
        // The raw grade
        $success = $success && table_column('quiz_states', '', 'raw_grade', 'varchar', '10', '', '', 'not null', 'grade');
        // For existing states (no penalties) this is equal to the grade
        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_states SET raw_grade = grade");
        // The penalty that the response attracted
        $success = $success && table_column('quiz_states', '', 'penalty', 'varchar', '10', '', '0.0', 'not null', 'raw_grade');
        // For existing states this can stay at 0 because penalties did not exist previously.
        /// New table for pointers to newest and newest graded states
        $success = $success && modify_database('', "CREATE TABLE `prefix_quiz_newest_states` (\n                             `id` int(10) unsigned NOT NULL auto_increment,\n                             `attemptid` int(10) unsigned NOT NULL default '0',\n                             `questionid` int(10) unsigned NOT NULL default '0',\n                             `new` int(10) unsigned NOT NULL default '0',\n                             `newgraded` int(10) unsigned NOT NULL default '0',\n                             `sumpenalty` varchar(10) NOT NULL default '0.0',\n                             PRIMARY KEY  (`id`),\n                             UNIQUE KEY `attemptid` (`attemptid`,`questionid`)\n                           ) TYPE=MyISAM COMMENT='Gives ids of the newest open and newest graded states';");
        /// Now upgrade some fields in states and newest_states tables where necessary
        // to save time on large sites only do this for attempts that have not yet been finished.
        if ($attempts = get_records_select('quiz_attempts', 'timefinish = 0')) {
            echo 'Update the states for the ' . count($attempts) . ' open attempts';
            // turn reporting off temporarily to avoid one line output per set_field
            $olddebug = $db->debug;
            $db->debug = false;
            foreach ($attempts as $attempt) {
                quiz_upgrade_states($attempt);
            }
            $db->debug = $olddebug;
        }
        /// Entries for the log_display table
        $success = $success && modify_database('', " INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('quiz', 'preview', 'quiz', 'name');");
        $success = $success && modify_database('', " INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('quiz', 'start attempt', 'quiz', 'name');");
        $success = $success && modify_database('', " INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('quiz', 'close attempt', 'quiz', 'name');");
        /// update the default settings in $CFG
        $review = QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_RESPONSES + QUIZ_REVIEW_SCORES;
        if (!empty($CFG->quiz_feedback)) {
            $review += QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_FEEDBACK;
        }
        if (!empty($CFG->quiz_correctanswers)) {
            $review += QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_ANSWERS;
        }
        if (isset($CFG->quiz_review) and $CFG->quiz_review & 1) {
            $review += QUIZ_REVIEW_CLOSED;
        }
        if (isset($CFG->quiz_review) and $CFG->quiz_review & 2) {
            $review += QUIZ_REVIEW_OPEN;
        }
        $success = $success && set_config('quiz_review', $review);
        /// Use tolerance instead of min and max in numerical question type
        $success = $success && table_column('quiz_numerical', '', 'tolerance', 'varchar', '255', '', '0.0', 'not null', 'answer');
        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_numerical SET tolerance = (max-min)/2");
        $success = $success && modify_database('', 'ALTER TABLE `prefix_quiz_numerical` DROP `min`');
        // Replaced by tolerance
        $success = $success && modify_database('', 'ALTER TABLE `prefix_quiz_numerical` DROP `max`');
        // Replaced by tolerance
        /// Tables for Remote Questions
        $success = $success && modify_database('', "CREATE TABLE `prefix_quiz_rqp` (\n                              `id` int(10) unsigned NOT NULL auto_increment,\n                              `question` int(10) unsigned NOT NULL default '0',\n                              `type` int(10) unsigned NOT NULL default '0',\n                              `source` longblob NOT NULL default '',\n                              `format` varchar(255) NOT NULL default '',\n                              `flags` tinyint(3) unsigned NOT NULL default '0',\n                              `maxscore` int(10) unsigned NOT NULL default '1',\n                              PRIMARY KEY  (`id`),\n                              KEY `question` (`question`)\n                              ) TYPE=MyISAM COMMENT='Options for RQP questions';");
        $success = $success && modify_database('', "CREATE TABLE `prefix_quiz_rqp_type` (\n                              `id` int(10) unsigned NOT NULL auto_increment,\n                              `name` varchar(255) NOT NULL default '',\n                              `rendering_server` varchar(255) NOT NULL default '',\n                              `cloning_server` varchar(255) NOT NULL default '',\n                              `flags` tinyint(3) NOT NULL default '0',\n                              PRIMARY KEY  (`id`),\n                              UNIQUE KEY `name` (`name`)\n                              ) TYPE=MyISAM COMMENT='RQP question types and the servers to be used to process them';");
        $success = $success && modify_database('', "CREATE TABLE `prefix_quiz_rqp_states` (\n                              `id` int(10) unsigned NOT NULL auto_increment,\n                              `stateid` int(10) unsigned NOT NULL default '0',\n                              `responses` text NOT NULL default '',\n                              `persistent_data` text NOT NULL default '',\n                              `template_vars` text NOT NULL default '',\n                              PRIMARY KEY  (`id`)\n                              ) TYPE=MyISAM COMMENT='RQP question type specific state information';");
    }
    if ($success && $oldversion < 2005050300) {
        // length of question determines question numbering. Currently all questions require one
        // question number except for DESCRIPTION questions.
        $success = $success && table_column('quiz_questions', '', 'length', 'integer', '10', 'unsigned', '1', 'not null', 'qtype');
        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_questions SET length = 0 WHERE qtype ='7'");
    }
    if ($success && $oldversion < 2005050408) {
        $success = $success && table_column('quiz_questions', '', 'penalty', 'float', '', '', '0.1', 'not null', 'defaultgrade');
        $success = $success && table_column('quiz_newest_states', 'new', 'newest', 'integer', '10', 'unsigned', '0', 'not null');
    }
    if ($success && $oldversion < 2005051400) {
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_rqp_type RENAME prefix_quiz_rqp_types;');
        $success = $success && modify_database('', "CREATE TABLE `prefix_quiz_rqp_servers` (\n                      id int(10) unsigned NOT NULL auto_increment,\n                      typeid int(10) unsigned NOT NULL default '0',\n                      url varchar(255) NOT NULL default '',\n                      can_render tinyint(2) unsigned NOT NULL default '0',\n                      can_author tinyint(2) unsigned NOT NULL default '0',\n                      PRIMARY KEY  (id)\n                    ) TYPE=MyISAM COMMENT='Information about RQP servers';");
        if ($types = get_records('quiz_rqp_types')) {
            foreach ($types as $type) {
                $server = new stdClass();
                $server->typeid = $type->id;
                $server->url = $type->rendering_server;
                $server->can_render = 1;
                $success = $success && insert_record('quiz_rqp_servers', $server);
            }
        }
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_rqp_types DROP rendering_server');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_rqp_types DROP cloning_server');
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_rqp_types DROP flags');
    }
    if ($success && $oldversion < 2005051401) {
        // Some earlier changes are undone here, so we need another condition
        if ($oldversion >= 2005042900) {
            // Restore the answer field
            $success = $success && table_column('quiz_numerical', '', 'answer', 'integer', '10', 'unsigned', '0', 'not null', 'answers');
            $singleanswer = array();
            if ($numericals = get_records('quiz_numerical')) {
                $numericals = array_values($numericals);
                $n = count($numericals);
                for ($i = 0; $i < $n; $i++) {
                    $numerical =& $numericals[$i];
                    if (strpos($numerical->answers, ',')) {
                        // comma separated list?
                        // Back this up to delete the record after the new ones are created
                        $id = $numerical->id;
                        unset($numerical->id);
                        // We need to create a record for each answer id
                        $answers = explode(',', $numerical->answers);
                        foreach ($answers as $answer) {
                            $numerical->answer = $answer;
                            $success = $success && insert_record('quiz_numerical', $numerical);
                        }
                        // ... and get rid of the old record
                        $success = $success && delete_records('quiz_numerical', 'id', $id);
                    } else {
                        $singleanswer[] = $numerical->id;
                    }
                }
            }
            // Do all of these at once
            if (!empty($singleanswer)) {
                $singleanswer = implode(',', $singleanswer);
                $success = $success && modify_database('', "UPDATE prefix_quiz_numerical SET answer = answers WHERE id IN ({$singleanswer});");
            }
            // All answer fields are set, so we can delete the answers field
            $success = $success && modify_database('', 'ALTER TABLE `prefix_quiz_numerical` DROP `answers`');
            // If the earlier changes weren't made we can safely do only the
            // bits here.
        } else {
            // Comma separated questionids will be stored as sequence
            $success = $success && table_column('quiz_multianswers', '', 'sequence', 'varchar', '255', '', '', 'not null', 'question');
            // Change the type of positionkey to int, so that the sorting works!
            $success = $success && table_column('quiz_multianswers', 'positionkey', 'positionkey', 'integer', '10', 'unsigned', '0', 'not null', '');
            $success = $success && table_column('quiz_questions', '', 'parent', 'integer', '10', 'unsigned', '0', 'not null', 'category');
            $success = $success && modify_database('', "UPDATE prefix_quiz_questions SET parent = id WHERE qtype ='" . RANDOM . "';");
            // Each multianswer record is converted to a question object and then
            // inserted as a new question into the quiz_questions table.
            // After that the question fields in the quiz_answers table and the
            // qtype specific tables are updated to point to the new question id.
            // Note: The quiz_numerical table is different as it stores one record
            //       per defined answer (to allow different tolerance values for
            //       different possible answers. (Currently multiple answers are
            //       not supported by the numerical editing interface, but
            //       all processing code does support that possibility.
            if ($multianswers = get_records_sql("SELECT m.id, q.category, " . "q.id AS parent, " . "q.name, q.questiontextformat, " . "m.norm AS defaultgrade, " . "m.answertype AS qtype, " . "q.version, q.hidden, m.answers, " . "m.positionkey " . "FROM {$CFG->prefix}quiz_questions q, " . "     {$CFG->prefix}quiz_multianswers m " . "WHERE q.qtype = '" . MULTIANSWER . "' " . "AND   q.id = m.question " . "ORDER BY q.id ASC, m.positionkey ASC")) {
                // ordered by positionkey
                $multianswers = array_values($multianswers);
                $n = count($multianswers);
                $parent = $multianswers[0]->parent;
                $sequence = array();
                $positions = array();
                // Turn reporting off temporarily to avoid one line output per set_field
                global $db;
                $olddebug = $db->debug;
                $db->debug = false;
                echo 'Now updating ' . $n . ' cloze questions.';
                for ($i = 0; $i < $n; $i++) {
                    // Backup these two values before unsetting the object fields
                    $answers = $multianswers[$i]->answers;
                    unset($multianswers[$i]->answers);
                    $pos = $multianswers[$i]->positionkey;
                    unset($multianswers[$i]->positionkey);
                    // Needed for substituting multianswer ids with position keys in the $state->answer field
                    $positions[$multianswers[$i]->id] = $pos;
                    // Create questions for all the multianswer victims
                    unset($multianswers[$i]->id);
                    $multianswers[$i]->length = 0;
                    $multianswers[$i]->questiontext = '';
                    $multianswers[$i]->stamp = make_unique_id_code();
                    $multianswers[$i]->name = addslashes($multianswers[$i]->name);
                    // $multianswers[$i]->parent is set in the query
                    // $multianswers[$i]->defaultgrade is set in the query
                    // $multianswers[$i]->qtype is set in the query
                    $id = insert_record('quiz_questions', $multianswers[$i]);
                    $success = $success && $id;
                    $sequence[$pos] = $id;
                    // Update the quiz_answers table to point to these new questions
                    $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_answers SET question = '{$id}' WHERE id IN ({$answers})", false);
                    // Update the questiontype tables to point to these new questions
                    if (SHORTANSWER == $multianswers[$i]->qtype) {
                        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_shortanswer SET question = '{$id}' WHERE answers = '{$answers}'", false);
                    } else {
                        if (MULTICHOICE == $multianswers[$i]->qtype) {
                            $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_multichoice SET question = '{$id}' WHERE answers = '{$answers}'", false);
                        } else {
                            if (NUMERICAL == $multianswers[$i]->qtype) {
                                $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_numerical SET question = '{$id}' WHERE answer IN ({$answers})", false);
                            }
                        }
                    }
                    // Whenever we're through with the subquestions of one multianswer
                    // question we delete the old records in the multianswers table,
                    // store a new record with the sequence in the multianswers table
                    // and point $parent to the next multianswer question.
                    if (!isset($multianswers[$i + 1]) || $parent != $multianswers[$i + 1]->parent) {
                        // Substituting multianswer ids with position keys in the $state->answer field
                        if ($states = get_records('quiz_states', 'question', $parent)) {
                            foreach ($states as $state) {
                                $reg = array();
                                preg_match_all('/(?:^|,)([0-9]+)-([^,]*)/', $state->answer, $reg);
                                $state->answer = '';
                                $m = count($reg[1]);
                                for ($j = 0; $j < $m; $j++) {
                                    if (isset($positions[$reg[1][$j]])) {
                                        $state->answer .= $positions[$reg[1][$j]] . '-' . $reg[2][$j] . ',';
                                    } else {
                                        notify("Undefined multianswer id ({$reg[1][$j]}) used in state #{$state->id}!");
                                        $state->answer .= $j + 1 . '-' . $reg[2][$j] . ',';
                                    }
                                }
                                $state->answer = rtrim($state->answer, ',');
                                // strip trailing comma
                                $success = $success && update_record('quiz_states', $state);
                            }
                        }
                        $success = $success && delete_records('quiz_multianswers', 'question', $parent);
                        $multi = new stdClass();
                        $multi->question = $parent;
                        $multi->sequence = implode(',', $sequence);
                        $success = $success && insert_record('quiz_multianswers', $multi);
                        if (isset($multianswers[$i + 1])) {
                            $parent = $multianswers[$i + 1]->parent;
                            $sequence = array();
                            $positions = array();
                        }
                    }
                }
                $db->debug = $olddebug;
            }
            // Remove redundant fields from quiz_multianswers
            $success = $success && modify_database('', 'ALTER TABLE `prefix_quiz_multianswers` DROP `answers`');
            $success = $success && modify_database('', 'ALTER TABLE `prefix_quiz_multianswers` DROP `positionkey`');
            $success = $success && modify_database('', 'ALTER TABLE `prefix_quiz_multianswers` DROP `answertype`');
            $success = $success && modify_database('', 'ALTER TABLE `prefix_quiz_multianswers` DROP `norm`');
        }
    }
    if ($success && $oldversion < 2005052004) {
        // We need to remove some duplicate entries that may be present in some databases
        // due to a faulty restore script
        // Remove duplicate entries from quiz_numerical
        if ($dups = get_records_sql("\n                SELECT question, answer, count(*) as num\n                FROM {$CFG->prefix}quiz_numerical\n                GROUP BY question, answer\n                HAVING count(*) > 1")) {
            foreach ($dups as $dup) {
                $ids = get_records_sql("\n                    SELECT id, id\n                    FROM {$CFG->prefix}quiz_numerical\n                    WHERE question = '{$dup->question}'\n                    AND answer = '{$dup->answer}'");
                $skip = true;
                foreach ($ids as $id) {
                    if ($skip) {
                        $skip = false;
                    } else {
                        $success = $success && delete_records('quiz_numerical', 'id', $id->id);
                    }
                }
            }
        }
        // Remove duplicate entries from quiz_shortanswer
        if ($dups = get_records_sql("\n                SELECT question, answers, count(*) as num\n                FROM {$CFG->prefix}quiz_shortanswer\n                GROUP BY question, answers\n                HAVING count(*) > 1")) {
            foreach ($dups as $dup) {
                $ids = get_records_sql("\n                    SELECT id, id\n                    FROM {$CFG->prefix}quiz_shortanswer\n                    WHERE question = '{$dup->question}'\n                    AND answers = '{$dup->answers}'");
                $skip = true;
                foreach ($ids as $id) {
                    if ($skip) {
                        $skip = false;
                    } else {
                        $success = $success && delete_records('quiz_shortanswer', 'id', $id->id);
                    }
                }
            }
        }
        // Remove duplicate entries from quiz_multichoice
        if ($dups = get_records_sql("\n                SELECT question, answers, count(*) as num\n                FROM {$CFG->prefix}quiz_multichoice\n                GROUP BY question, answers\n                HAVING count(*) > 1")) {
            foreach ($dups as $dup) {
                $ids = get_records_sql("\n                    SELECT id, id\n                    FROM {$CFG->prefix}quiz_multichoice\n                    WHERE question = '{$dup->question}'\n                    AND answers = '{$dup->answers}'");
                $skip = true;
                foreach ($ids as $id) {
                    if ($skip) {
                        $skip = false;
                    } else {
                        $success = $success && delete_records('quiz_multichoice', 'id', $id->id);
                    }
                }
            }
        }
    }
    if ($success && $oldversion < 2005060300) {
        //Search all the orphan categories (those whose course doesn't exist)
        //and process them, deleting or moving them to site course - Bug 2459
        //Set debug to false
        $olddebug = $db->debug;
        $db->debug = false;
        //Iterate over all the quiz_categories records to get their course id
        if ($courses = get_records_sql("SELECT DISTINCT course as id, course\n                                         FROM {$CFG->prefix}quiz_categories")) {
            //Iterate over courses
            foreach ($courses as $course) {
                //If the course doesn't exist, orphan category found!
                //Process it with question_delete_course(). It will do all the hard work.
                if (!record_exists('course', 'id', $course->id)) {
                    require_once "{$CFG->libdir}/questionlib.php";
                    $success = $success && question_delete_course($course);
                }
            }
        }
        //Reset rebug to its original state
        $db->debug = $olddebug;
    }
    if ($success && $oldversion < 2005062600) {
        $success = $success && modify_database('', "\n            CREATE TABLE `prefix_quiz_essay` (\n                `id` int(10) unsigned NOT NULL auto_increment,\n                `question` int(10) unsigned NOT NULL default '0',\n                `answer` varchar(255) NOT NULL default '',\n                PRIMARY KEY  (`id`),\n                KEY `question` (`question`)\n           ) TYPE=MyISAM COMMENT='Options for essay questions'");
        $success = $success && modify_database('', "\n            CREATE TABLE `prefix_quiz_essay_states` (\n              `id` int(10) unsigned NOT NULL auto_increment,\n              `stateid` int(10) unsigned NOT NULL default '0',\n              `graded` tinyint(4) unsigned NOT NULL default '0',\n              `fraction` varchar(10) NOT NULL default '0.0',\n              `response` text NOT NULL,\n              PRIMARY KEY  (`id`)\n            ) TYPE=MyISAM COMMENT='essay question type specific state information'");
    }
    if ($success && $oldversion < 2005070202) {
        // add new unique id to prepare the way for lesson module to have its own attempts table
        $success = $success && table_column('quiz_attempts', '', 'uniqueid', 'integer', '10', 'unsigned', '0', 'not null', 'id');
        // initially we can use the id as the unique id because no other modules use attempts yet.
        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_attempts SET uniqueid = id", false);
        // we set $CFG->attemptuniqueid to the next available id
        $record = get_record_sql("SELECT max(id)+1 AS nextid FROM {$CFG->prefix}quiz_attempts");
        $success = $success && set_config('attemptuniqueid', empty($record->nextid) ? 1 : $record->nextid);
    }
    if ($success && $oldversion < 2006020801) {
        // add new field to store time delay between the first and second quiz attempt
        $success = $success && table_column('quiz', '', 'delay1', 'integer', '10', 'unsigned', '0', 'not null', 'popup');
        // add new field to store time delay between the second and any additional quizes
        $success = $success && table_column('quiz', '', 'delay2', 'integer', '10', 'unsigned', '0', 'not null', 'delay1');
    }
    if ($success && $oldversion < 2006021101) {
        // set defaultgrade field properly (probably not necessary, but better make sure)
        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_questions SET defaultgrade = '1' WHERE defaultgrade = '0'", false);
        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_questions SET defaultgrade = '0' WHERE qtype = '7'", false);
    }
    if ($success && $oldversion < 2006021103) {
        // add new field to store the question-level shuffleanswers option
        $success = $success && table_column('quiz_match', '', 'shuffleanswers', 'tinyint', '4', 'unsigned', '1', 'not null', 'subquestions');
        $success = $success && table_column('quiz_multichoice', '', 'shuffleanswers', 'tinyint', '4', 'unsigned', '1', 'not null', 'single');
        $success = $success && table_column('quiz_randomsamatch', '', 'shuffleanswers', 'tinyint', '4', 'unsigned', '1', 'not null', 'choose');
    }
    if ($success && $oldversion < 2006021104) {
        // add originalversion field for the new versioning mechanism
        $success = $success && table_column('quiz_question_versions', '', 'originalquestion', 'int', '10', 'unsigned', '0', 'not null', 'newquestion');
    }
    if ($success && $oldversion < 2006021301) {
        $success = $success && modify_database('', 'ALTER TABLE prefix_quiz_attempts ADD UNIQUE INDEX uniqueid (uniqueid);');
    }
    if ($success && $oldversion < 2006021302) {
        $success = $success && table_column('quiz_match_sub', '', 'code', 'int', '10', 'unsigned', '0', 'not null', 'id');
        $success = $success && execute_sql("UPDATE {$CFG->prefix}quiz_match_sub SET code = id", false);
    }
    if ($success && $oldversion < 2006021304) {
        // convert sequence field to text to accomodate very long sequences, see bug 4257
        $success = $success && table_column('quiz_multianswers', 'sequence', 'sequence', 'text', '', '', '', 'not null', 'question');
    }
    if ($success && $oldversion < 2006021501) {
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_newest_states RENAME {$CFG->prefix}question_sessions", false);
    }
    if ($success && $oldversion < 2006022200) {
        // convert grade fields to float
        $success = $success && set_field('quiz_attempts', 'sumgrades', 0, 'sumgrades', '');
        $success = $success && table_column('quiz_attempts', 'sumgrades', 'sumgrades', 'float', '', '', '0', 'not null');
        $success = $success && set_field('quiz_answers', 'fraction', 0, 'fraction', '');
        $success = $success && table_column('quiz_answers', 'fraction', 'fraction', 'float', '', '', '0', 'not null');
        $success = $success && set_field('quiz_essay_states', 'fraction', 0, 'fraction', '');
        $success = $success && table_column('quiz_essay_states', 'fraction', 'fraction', 'float', '', '', '0', 'not null');
        $success = $success && set_field('quiz_states', 'grade', 0, 'grade', '');
        $success = $success && table_column('quiz_states', 'grade', 'grade', 'float', '', '', '0', 'not null');
        $success = $success && set_field('quiz_states', 'raw_grade', 0, 'raw_grade', '');
        $success = $success && table_column('quiz_states', 'raw_grade', 'raw_grade', 'float', '', '', '0', 'not null');
        $success = $success && set_field('quiz_states', 'penalty', 0, 'penalty', '');
        $success = $success && table_column('quiz_states', 'penalty', 'penalty', 'float', '', '', '0', 'not null');
        $success = $success && set_field('question_sessions', 'sumpenalty', 0, 'sumpenalty', '');
        $success = $success && table_column('question_sessions', 'sumpenalty', 'sumpenalty', 'float', '', '', '0', 'not null');
    }
    if ($success && $oldversion < 2006022400) {
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_questions RENAME {$CFG->prefix}question", false);
    }
    if ($success && $oldversion < 2006022402) {
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_states RENAME {$CFG->prefix}question_states", false);
    }
    if ($success && $oldversion < 2006022800) {
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_answers RENAME {$CFG->prefix}question_answers", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_categories RENAME {$CFG->prefix}question_categories", false);
    }
    if ($success && $oldversion < 2006031202) {
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_truefalse RENAME {$CFG->prefix}question_truefalse", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_shortanswer RENAME {$CFG->prefix}question_shortanswer", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_multianswers RENAME {$CFG->prefix}question_multianswer", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_multichoice RENAME {$CFG->prefix}question_multichoice", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_numerical RENAME {$CFG->prefix}question_numerical", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_numerical_units RENAME {$CFG->prefix}question_numerical_units", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_randomsamatch RENAME {$CFG->prefix}question_randomsamatch", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_match RENAME {$CFG->prefix}question_match", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_match_sub RENAME {$CFG->prefix}question_match_sub", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_calculated RENAME {$CFG->prefix}question_calculated", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_dataset_definitions RENAME {$CFG->prefix}question_dataset_definitions", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_dataset_items RENAME {$CFG->prefix}question_dataset_items", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_question_datasets RENAME {$CFG->prefix}question_datasets", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_rqp RENAME {$CFG->prefix}question_rqp", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_rqp_servers RENAME {$CFG->prefix}question_rqp_servers", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_rqp_states RENAME {$CFG->prefix}question_rqp_states", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_rqp_types RENAME {$CFG->prefix}question_rqp_types", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_essay RENAME {$CFG->prefix}question_essay", false);
        $success = $success && execute_sql("ALTER TABLE {$CFG->prefix}quiz_essay_states RENAME {$CFG->prefix}question_essay_states", false);
    }
    if ($success && $oldversion < 2006032100) {
        // change from the old questiontype numbers to using the questiontype names
        $success = $success && table_column('question', 'qtype', 'qtype', 'varchar', 20, '', '', 'not null');
        $success = $success && set_field('question', 'qtype', 'shortanswer', 'qtype', 1);
        $success = $success && set_field('question', 'qtype', 'truefalse', 'qtype', 2);
        $success = $success && set_field('question', 'qtype', 'multichoice', 'qtype', 3);
        $success = $success && set_field('question', 'qtype', 'random', 'qtype', 4);
        $success = $success && set_field('question', 'qtype', 'match', 'qtype', 5);
        $success = $success && set_field('question', 'qtype', 'randomsamatch', 'qtype', 6);
        $success = $success && set_field('question', 'qtype', 'description', 'qtype', 7);
        $success = $success && set_field('question', 'qtype', 'numerical', 'qtype', 8);
        $success = $success && set_field('question', 'qtype', 'multianswer', 'qtype', 9);
        $success = $success && set_field('question', 'qtype', 'calculated', 'qtype', 10);
        $success = $success && set_field('question', 'qtype', 'rqp', 'qtype', 11);
        $success = $success && set_field('question', 'qtype', 'essay', 'qtype', 12);
    }
    if ($success && $oldversion < 2006032200) {
        // set version for all questiontypes that already have their tables installed
        $success = $success && set_config('qtype_calculated_version', 2006032100);
        $success = $success && set_config('qtype_essay_version', 2006032100);
        $success = $success && set_config('qtype_match_version', 2006032100);
        $success = $success && set_config('qtype_multianswer_version', 2006032100);
        $success = $success && set_config('qtype_multichoice_version', 2006032100);
        $success = $success && set_config('qtype_numerical_version', 2006032100);
        $success = $success && set_config('qtype_randomsamatch_version', 2006032100);
        $success = $success && set_config('qtype_rqp_version', 2006032100);
        $success = $success && set_config('qtype_shortanswer_version', 2006032100);
        $success = $success && set_config('qtype_truefalse_version', 2006032100);
    }
    if ($success && $oldversion < 2006040600) {
        $success = $success && table_column('question_sessions', '', 'comment', 'text', '', '', '', 'not null', 'sumpenalty');
    }
    if ($success && $oldversion < 2006040900) {
        $success = $success && modify_database('', "UPDATE prefix_question SET parent = id WHERE qtype ='random';");
    }
    if ($success && $oldversion < 2006041000) {
        $success = $success && modify_database('', " INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('quiz', 'continue attempt', 'quiz', 'name');");
    }
    if ($success && $oldversion < 2006041001) {
        $success = $success && table_column('question', 'version', 'version', 'varchar', 255);
    }
    if ($success && $oldversion < 2006042800) {
        // Check we have some un-renamed tables (verified in some servers)
        if ($tables = $db->MetaTables('TABLES')) {
            if (in_array($CFG->prefix . 'quiz_randommatch', $tables) && !in_array($CFG->prefix . 'question_randomsamatch', $tables)) {
                $success = $success && modify_database("", "ALTER TABLE prefix_quiz_randommatch RENAME prefix_question_randomsamatch ");
            }
            // Check for one possible missing field in one table
            if ($columns = $db->MetaColumnNames($CFG->prefix . 'question_randomsamatch')) {
                if (!in_array('shuffleanswers', $columns)) {
                    $success = $success && table_column('question_randomsamatch', '', 'shuffleanswers', 'tinyint', '4', 'unsigned', '1', 'not null', 'choose');
                }
            }
        }
    }
    if ($oldversion < 2006051300) {
        // The newgraded field must always point to a valid state
        $success = $success && modify_database("", "UPDATE prefix_question_sessions SET newgraded = newest where newgraded = '0'");
        // Only perform this if hasn't been performed before (in MOODLE_16_STABLE branch - bug 5717)
        $tables = $db->MetaTables('TABLES');
        if (!in_array($CFG->prefix . 'question_attempts', $tables)) {
            // The following table is discussed in bug 5468
            $success = $success && modify_database("", "CREATE TABLE prefix_question_attempts (\n                                      id int(10) unsigned NOT NULL auto_increment,\n                                      modulename varchar(20) NOT NULL default 'quiz',\n                                      PRIMARY KEY  (id)\n                                    ) TYPE=MyISAM COMMENT='Student attempts. This table gets extended by the modules';");
            // create one entry for all the existing quiz attempts
            $success = $success && modify_database("", "INSERT INTO prefix_question_attempts (id)\n                                       SELECT uniqueid\n                                       FROM prefix_quiz_attempts;");
        }
    }
    if ($success && $oldversion < 2006060700) {
        // fix for 5720
        // Copy the teacher comments from the question_essay_states table to the new
        // question_sessions table.
        // Get the attempt unique ID, teacher comment, graded flag, state ID, and question ID
        // based on the quesiont_essay_states
        if ($results = get_records_sql("SELECT a.uniqueid, es.response AS essaycomment, es.graded AS isgraded, \n                                               qs.id AS stateid, qs.question AS questionid \n                                        FROM {$CFG->prefix}question_states as qs,\n                                             {$CFG->prefix}question_essay_states es, \n                                             {$CFG->prefix}quiz_attempts a \n                                        WHERE es.stateid = qs.id AND a.uniqueid = qs.attempt")) {
            foreach ($results as $result) {
                // Create a state object to be used for updating
                $state = new stdClass();
                $state->id = $result->stateid;
                if ($result->isgraded) {
                    // Graded - save comment to the sessions and change state event to QUESTION_EVENTMANUALGRADE
                    if (!($success = $success && set_field('question_sessions', 'comment', $result->essaycomment, 'attemptid', $result->uniqueid, 'questionid', $result->questionid))) {
                        notify("Essay Table Migration: Cannot save comment");
                        break;
                    }
                    $state->event = 9;
                    //QUESTION_EVENTMANUALGRADE;
                } else {
                    // Not graded
                    $state->event = 7;
                    //QUESTION_EVENTSUBMIT;
                }
                // Save the event
                if (!($success = $success && update_record('question_states', $state))) {
                    notify("Essay Table Migration: Cannot update state");
                    break;
                }
            }
        }
        // dropping unused tables
        $success = $success && execute_sql('DROP TABLE ' . $CFG->prefix . 'question_essay_states');
        $success = $success && execute_sql('DROP TABLE ' . $CFG->prefix . 'question_essay');
        $success = $success && execute_sql('DROP TABLE ' . $CFG->prefix . 'quiz_attemptonlast_datasets', false);
    }
    if ($oldversion < 2006081000) {
        // Add a column to the the question table to store the question general feedback.
        $success = $success && table_column('question', '', 'commentarytext', 'text', '', '', '', 'not null', 'image');
        // Adjust the quiz review options so that general feedback is displayed whenever feedback is.
        $success = $success && execute_sql('UPDATE ' . $CFG->prefix . 'quiz SET review = ' . '(review & ~' . QUIZ_REVIEW_GENERALFEEDBACK . ') | ' . '((review & ' . QUIZ_REVIEW_FEEDBACK . ') * 8)');
        // Set the general feedback bits to be the same as the feedback ones.
        // Same adjustment to the defaults for new quizzes.
        $success = $success && set_config('quiz_review', $CFG->quiz_review & ~QUIZ_REVIEW_GENERALFEEDBACK | ($CFG->quiz_review & QUIZ_REVIEW_FEEDBACK) << 3);
    }
    if ($success && $oldversion < 2006081400) {
        $success = $success && modify_database('', "\n            CREATE TABLE prefix_quiz_feedback (\n                id int(10) unsigned NOT NULL auto_increment,\n                quizid int(10) unsigned NOT NULL default '0',\n                feedbacktext text NOT NULL default '',\n                mingrade double NOT NULL default '0',\n                maxgrade double NOT NULL default '0',\n                PRIMARY KEY (id),\n                KEY quizid (quizid)\n            ) TYPE=MyISAM COMMENT='Feedback given to students based on their overall score on the test';\n        ");
        $success = $success && execute_sql("\n            INSERT INTO {$CFG->prefix}quiz_feedback (quizid, feedbacktext, maxgrade, mingrade)\n            SELECT id, '', grade + 1, 0 FROM {$CFG->prefix}quiz;\n        ");
    }
    if ($success && $oldversion < 2006082400) {
        $success = $success && table_column('question_sessions', 'comment', 'manualcomment', 'text', '', '', '');
    }
    if ($success && $oldversion < 2006091900) {
        $success = $success && table_column('question_dataset_items', 'number', 'itemnumber', 'integer');
    }
    if ($success && $oldversion < 2006091901) {
        $success = $success && table_column('question', 'commentarytext', 'generalfeedback', 'text', '', '', '');
    }
    //////  DO NOT ADD NEW THINGS HERE!!  USE upgrade.php and the lib/ddllib.php functions.
    return $success;
}
Example #27
0
function fix_orphaned_questions($course)
{
    global $CFG;
    $categories = get_records_sql("SELECT DISTINCT t.category, t.category\n                                       FROM {$CFG->prefix}question t,\n                                            {$CFG->prefix}quiz_question_instances g,\n                                            {$CFG->prefix}quiz q\n                                       WHERE q.course = '{$course}' AND\n                                             g.quiz = q.id AND\n                                             g.question = t.id", false);
    if ($categories) {
        foreach ($categories as $key => $category) {
            $exist = get_record('question_categories', 'id', $key);
            //If the category doesn't exist
            if (!$exist) {
                //Build a new category
                $db_cat = new stdClass();
                $db_cat->course = $course;
                $db_cat->name = get_string('recreatedcategory', '', $key);
                $db_cat->info = get_string('recreatedcategory', '', $key);
                $db_cat->publish = 1;
                $db_cat->stamp = make_unique_id_code();
                //Insert the new category
                $catid = insert_record('question_categories', $db_cat);
                unset($db_cat);
                if ($catid) {
                    //Reasign orphaned questions to their new category
                    set_field('question', 'category', $catid, 'category', $key);
                }
            }
        }
    }
}
function RWSAAQRand()
{
    global $CFG;
    global $DB;
    global $RWSUID;
    RWSCMAuth();
    RWSCRAuth();
    RWSCMUSvc();
    RWSCMMaint();
    $r_pm = RWSGSOpt("quizid", PARAM_ALPHANUM);
    if ($r_pm === false || strlen($r_pm) == 0) {
        RWSSErr("2067");
    }
    $r_qzmi = intval($r_pm);
    $r_cmod = RWSCMUQuiz($r_qzmi);
    $r_cid = $r_cmod->course;
    RWSCMUCourse($r_cid, true);
    $r_mr = $DB->get_record("modules", array("id" => $r_cmod->module));
    if ($r_mr === false) {
        RWSSErr("2043");
    }
    $r_qiz = $DB->get_record($r_mr->name, array("id" => $r_cmod->instance));
    if ($r_qiz === false) {
        RWSSErr("2044");
    }
    $r_pm = RWSGSOpt("qcatid", PARAM_ALPHANUM);
    if ($r_pm === false || strlen($r_pm) == 0) {
        RWSSErr("2064");
    }
    $r_qci = intval($r_pm);
    $r_qca = $DB->get_record("question_categories", array("id" => $r_qci));
    if ($r_qca === false) {
        RWSSErr("2065");
    }
    if (respondusws_floatcompare($CFG->version, 2013111800, 2) >= 0) {
        $r_ctx = context::instance_by_id($r_qca->contextid);
    } else {
        $r_ctx = get_context_instance_by_id($r_qca->contextid);
    }
    $r_qcci = RWSGCFCat($r_ctx);
    if ($r_qcci != $r_cid) {
        if (is_siteadmin($RWSUID)) {
            if ($r_qcci != SITEID) {
                RWSSErr("2109");
            }
        } else {
            RWSSErr("2084");
        }
    }
    $r_pm = RWSGSOpt("qcount", PARAM_ALPHANUM);
    if ($r_pm === false || strlen($r_pm) == 0) {
        RWSSErr("2085");
    }
    $r_qct = intval($r_pm);
    if ($r_qct <= 0) {
        RWSSErr("2085");
    }
    $r_pm = RWSGSOpt("qgrade", PARAM_NOTAGS);
    if ($r_pm === false || strlen($r_pm) == 0) {
        RWSSErr("2086");
    }
    $r_qg = round(floatval($r_pm));
    if ($r_qg <= 0) {
        RWSSErr("2086");
    }
    $r_mr = $DB->get_record("modules", array("id" => $r_cmod->module));
    if ($r_mr === false) {
        RWSSErr("2043");
    }
    $r_qiz = $DB->get_record($r_mr->name, array("id" => $r_cmod->instance));
    if ($r_qiz === false) {
        RWSSErr("2044");
    }
    if (!isset($r_qiz->instance)) {
        $r_qiz->instance = $r_qiz->id;
    }
    $r_aerr = 0;
    for ($r_i = 0; $r_i < $r_qct; $r_i++) {
        $r_qst = new stdClass();
        $r_qst->qtype = RWSRND;
        $r_qst->parent = 0;
        $r_qst->hidden = 0;
        $r_qst->length = 1;
        $r_qst->questiontext = 1;
        if (respondusws_floatcompare($CFG->version, 2011070100, 2) >= 0) {
            $r_rqt = question_bank::get_qtype("random");
            $r_qst->name = $r_rqt->question_name($r_qca, !empty($r_qst->questiontext));
        } else {
            $r_qst->name = random_qtype::question_name($r_qca, !empty($r_qst->questiontext));
        }
        $r_qst->questiontextformat = FORMAT_HTML;
        $r_qst->penalty = 0;
        if (respondusws_floatcompare($CFG->version, 2011070100, 2) >= 0) {
            $r_qst->defaultmark = $r_qg;
        } else {
            $r_qst->defaultgrade = $r_qg;
        }
        $r_qst->generalfeedback = "";
        $r_qst->generalfeedbackformat = FORMAT_HTML;
        $r_qst->category = $r_qca->id;
        $r_qst->stamp = make_unique_id_code();
        $r_qst->createdby = $RWSUID;
        $r_qst->modifiedby = $RWSUID;
        $r_qst->timecreated = time();
        $r_qst->timemodified = time();
        $r_qst->id = $DB->insert_record("question", $r_qst);
        $DB->set_field("question", "parent", $r_qst->id, array("id" => $r_qst->id));
        $r_h = question_hash($r_qst);
        $DB->set_field("question", "version", $r_h, array("id" => $r_qst->id));
        if (respondusws_floatcompare($CFG->version, 2011070100, 2) >= 0) {
            quiz_add_quiz_question($r_qst->id, $r_qiz);
        } else {
            $r_ok = quiz_add_quiz_question($r_qst->id, $r_qiz);
            if (!$r_ok) {
                $DB->delete_records("question", array("id" => $r_qst->id));
                $r_aerr++;
            }
        }
    }
    if ($r_aerr > 0) {
        RWSSErr("2087,{$r_aerr}");
    }
    if ($r_aerr < $r_qct) {
        quiz_delete_previews($r_qiz);
    }
    if (respondusws_floatcompare($CFG->version, 2014051200, 2) >= 0) {
        quiz_update_sumgrades($r_qiz);
    } else {
        $r_qiz->grades = quiz_get_all_question_grades($r_qiz);
        $r_sumg = array_sum($r_qiz->grades);
        $DB->set_field("quiz", "sumgrades", $r_sumg, array("id" => $r_qiz->id));
    }
    RWSSStat("1006");
}
Example #29
0
    /**
     * find and/or create the category described by a delimited list
     * e.g. $course$/tom/dick/harry or tom/dick/harry
     *
     * removes any context string no matter whether $getcontext is set
     * but if $getcontext is set then ignore the context and use selected category context.
     *
     * @param string catpath delimited category path
     * @param int courseid course to search for categories
     * @return mixed category object or null if fails
     */
    protected function create_category_path($catpath) {
        global $DB;
        $catnames = $this->split_category_path($catpath);
        $parent = 0;
        $category = null;

        // check for context id in path, it might not be there in pre 1.9 exports
        $matchcount = preg_match('/^\$([a-z]+)\$$/', $catnames[0], $matches);
        if ($matchcount == 1) {
            $contextid = $this->translator->string_to_context($matches[1]);
            array_shift($catnames);
        } else {
            $contextid = false;
        }

        if ($this->contextfromfile && $contextid !== false) {
            $context = get_context_instance_by_id($contextid);
            require_capability('moodle/question:add', $context);
        } else {
            $context = get_context_instance_by_id($this->category->contextid);
        }

        // Now create any categories that need to be created.
        foreach ($catnames as $catname) {
            if ($category = $DB->get_record('question_categories',
                    array('name' => $catname, 'contextid' => $context->id, 'parent' => $parent))) {
                $parent = $category->id;
            } else {
                require_capability('moodle/question:managecategory', $context);
                // create the new category
                $category = new stdClass();
                $category->contextid = $context->id;
                $category->name = $catname;
                $category->info = '';
                $category->parent = $parent;
                $category->sortorder = 999;
                $category->stamp = make_unique_id_code();
                $id = $DB->insert_record('question_categories', $category);
                $category->id = $id;
                $parent = $id;
            }
        }
        return $category;
    }
Example #30
0
            quiz_add_quiz_question($existingquestion->id, $quiz);
            $randomcount--;
        }
    }
    // If more are needed, create them.
    if ($randomcount > 0) {
        $form->questiontext = $recurse;
        // we use the questiontext field to store the info
        // on whether to include questions in subcategories
        $form->questiontextformat = 0;
        $form->image = '';
        $form->defaultgrade = 1;
        $form->hidden = 1;
        for ($i = 0; $i < $randomcount; $i++) {
            $form->category = "{$category->id},{$category->contextid}";
            $form->stamp = make_unique_id_code();
            // Set the unique code (not to be changed)
            $question = new stdClass();
            $question->qtype = RANDOM;
            $question = $QTYPES[RANDOM]->save_question($question, $form, $course);
            if (!isset($question->id)) {
                error('Could not insert new random question!');
            }
            quiz_add_quiz_question($question->id, $quiz);
        }
    }
    $significantchangemade = true;
}
if (optional_param('repaginate', false, PARAM_BOOL) and confirm_sesskey()) {
    /// Re-paginate the quiz
    $questionsperpage = optional_param('questionsperpage', $quiz->questionsperpage, PARAM_INT);