. /** * Upgrade script for the quiz module. * * @package mod_quiz * @copyright 2006 Eloy Lafuente (stronk7) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Quiz module upgrade function. * @param string $oldversion the version we are upgrading from. */ function xmldb_quiz_upgrade($oldversion) { global $CFG, $DB; $dbman = $DB->get_manager(); // Moodle v2.2.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2011120700) { // Define field lastcron to be dropped from quiz_reports. $table = new xmldb_table('quiz_reports'); $field = new xmldb_field('lastcron'); // Conditionally launch drop field lastcron. if ($dbman->field_exists($table, $field)) { $dbman->drop_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2011120700, 'quiz'); } if ($oldversion < 2011120701) { // Define field cron to be dropped from quiz_reports. $table = new xmldb_table('quiz_reports'); $field = new xmldb_field('cron'); // Conditionally launch drop field cron. if ($dbman->field_exists($table, $field)) { $dbman->drop_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2011120701, 'quiz'); } if ($oldversion < 2011120703) { // Track page of quiz attempts. $table = new xmldb_table('quiz_attempts'); $field = new xmldb_field('currentpage', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, 0); if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } upgrade_mod_savepoint(true, 2011120703, 'quiz'); } if ($oldversion < 2012030901) { // Configuration option for navigation method. $table = new xmldb_table('quiz'); $field = new xmldb_field('navmethod', XMLDB_TYPE_CHAR, '16', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, 'free'); if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } upgrade_mod_savepoint(true, 2012030901, 'quiz'); } if ($oldversion < 2012040198) { // This step was added later. In MDL-32727, it was found that adding the // unique index on quiz-userid-attempt sometimes failed because of // duplicate entries {quizid}-{userid}-{attempt}. We do two things to // prevent these problems. First, here, we delete all preview attempts. // This code is an approximate copy-and-paste from // question_engine_data_mapper::delete_questions_usage_by_activities // Note that, for simplicity, the MySQL performance hack has been removed. // Since this code is for upgrade only, performance in not so critical, // where as simplicity of testing the code is. // Note that there is a limit to how far I am prepared to go in eliminating // all calls to library functions in this upgrade code. The only library // function still being used in question_engine::get_all_response_file_areas(); // I think it is pretty safe not to inline it here. // Get a list of response variables that have files. require_once($CFG->dirroot . '/question/type/questiontypebase.php'); $variables = array(); foreach (core_component::get_plugin_list('qtype') as $qtypename => $path) { $file = $path . '/questiontype.php'; if (!is_readable($file)) { continue; } include_once($file); $class = 'qtype_' . $qtypename; if (!class_exists($class)) { continue; } $qtype = new $class(); if (!method_exists($qtype, 'response_file_areas')) { continue; } $variables += $qtype->response_file_areas(); } // Conver that to a list of actual file area names. $fileareas = array(); foreach (array_unique($variables) as $variable) { $fileareas[] = 'response_' . $variable; } // No point checking if this is empty as an optimisation, because essay // has response file areas, so the array will never be empty. // Get all the contexts where there are previews. $contextids = $DB->get_records_sql_menu(" SELECT DISTINCT qu.contextid, 1 FROM {question_usages} qu JOIN {quiz_attempts} quiza ON quiza.uniqueid = qu.id WHERE quiza.preview = 1"); // Loop over contexts and files areas, deleting all files. $fs = get_file_storage(); foreach ($contextids as $contextid => $notused) { foreach ($fileareas as $filearea) { upgrade_set_timeout(300); $fs->delete_area_files_select($contextid, 'question', $filearea, "IN (SELECT qas.id FROM {question_attempt_steps} qas JOIN {question_attempts} qa ON qa.id = qas.questionattemptid JOIN {quiz_attempts} quiza ON quiza.uniqueid = qa.questionusageid WHERE quiza.preview = 1)"); } } // Now delete the question data associated with the previews. $DB->delete_records_select('question_attempt_step_data', "attemptstepid IN ( SELECT qas.id FROM {question_attempt_steps} qas JOIN {question_attempts} qa ON qa.id = qas.questionattemptid JOIN {quiz_attempts} quiza ON quiza.uniqueid = qa.questionusageid WHERE quiza.preview = 1)"); $DB->delete_records_select('question_attempt_steps', "questionattemptid IN ( SELECT qa.id FROM {question_attempts} qa JOIN {quiz_attempts} quiza ON quiza.uniqueid = qa.questionusageid WHERE quiza.preview = 1)"); $DB->delete_records_select('question_attempts', "{question_attempts}.questionusageid IN ( SELECT uniqueid FROM {quiz_attempts} WHERE preview = 1)"); $DB->delete_records_select('question_usages', "{question_usages}.id IN ( SELECT uniqueid FROM {quiz_attempts} WHERE preview = 1)"); // Finally delete the previews. $DB->delete_records('quiz_attempts', array('preview' => 1)); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040198, 'quiz'); } if ($oldversion < 2012040199) { // This step was added later. In MDL-32727, it was found that adding the // unique index on quiz-userid-attempt sometimes failed because of // duplicate entries {quizid}-{userid}-{attempt}. // Here, if there are still duplicate entires, we renumber the values in // the attempt column. // Load all the problem quiz attempts. $problems = $DB->get_recordset_sql(' SELECT qa.id, qa.quiz, qa.userid, qa.attempt FROM {quiz_attempts} qa JOIN ( SELECT DISTINCT quiz, userid FROM {quiz_attempts} GROUP BY quiz, userid, attempt HAVING COUNT(1) > 1 ) problems_view ON problems_view.quiz = qa.quiz AND problems_view.userid = qa.userid ORDER BY qa.quiz, qa.userid, qa.attempt, qa.id'); // Renumber them. $currentquiz = null; $currentuserid = null; $attempt = 1; foreach ($problems as $problem) { if ($problem->quiz !== $currentquiz || $problem->userid !== $currentuserid) { $currentquiz = $problem->quiz; $currentuserid = $problem->userid; $attempt = 1; } if ($attempt != $problem->attempt) { $DB->set_field('quiz_attempts', 'attempt', $attempt, array('id' => $problem->id)); } $attempt += 1; } $problems->close(); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040199, 'quiz'); } if ($oldversion < 2012040200) { // Define index userid to be dropped form quiz_attempts $table = new xmldb_table('quiz_attempts'); $index = new xmldb_index('userid', XMLDB_INDEX_NOTUNIQUE, array('userid')); // Conditionally launch drop index quiz-userid-attempt. if ($dbman->index_exists($table, $index)) { $dbman->drop_index($table, $index); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040200, 'quiz'); } if ($oldversion < 2012040201) { // Define key userid (foreign) to be added to quiz_attempts. $table = new xmldb_table('quiz_attempts'); $key = new xmldb_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id')); // Launch add key userid. $dbman->add_key($table, $key); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040201, 'quiz'); } if ($oldversion < 2012040202) { // Define index quiz-userid-attempt (unique) to be added to quiz_attempts. $table = new xmldb_table('quiz_attempts'); $index = new xmldb_index('quiz-userid-attempt', XMLDB_INDEX_UNIQUE, array('quiz', 'userid', 'attempt')); // Conditionally launch add index quiz-userid-attempt. if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040202, 'quiz'); } if ($oldversion < 2012040203) { // Define field state to be added to quiz_attempts. $table = new xmldb_table('quiz_attempts'); $field = new xmldb_field('state', XMLDB_TYPE_CHAR, '16', null, XMLDB_NOTNULL, null, 'inprogress', 'preview'); // Conditionally launch add field state. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040203, 'quiz'); } if ($oldversion < 2012040204) { // Update quiz_attempts.state for finished attempts. $DB->set_field_select('quiz_attempts', 'state', 'finished', 'timefinish > 0'); // Other, more complex transitions (basically abandoned attempts), will // be handled by cron later. // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040204, 'quiz'); } if ($oldversion < 2012040205) { // Define field overduehandling to be added to quiz. $table = new xmldb_table('quiz'); $field = new xmldb_field('overduehandling', XMLDB_TYPE_CHAR, '16', null, XMLDB_NOTNULL, null, 'autoabandon', 'timelimit'); // Conditionally launch add field overduehandling. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040205, 'quiz'); } if ($oldversion < 2012040206) { // Define field graceperiod to be added to quiz. $table = new xmldb_table('quiz'); $field = new xmldb_field('graceperiod', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'overduehandling'); // Conditionally launch add field graceperiod. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012040206, 'quiz'); } // Moodle v2.3.0 release upgrade line // Put any upgrade step following this if ($oldversion < 2012061702) { // MDL-32791 somebody reported having nonsense rows in their // quiz_question_instances which caused various problems. These rows // are meaningless, hence this upgrade step to clean them up. $DB->delete_records('quiz_question_instances', array('question' => 0)); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012061702, 'quiz'); } if ($oldversion < 2012061703) { // MDL-34702 the questiondecimalpoints column was created with default -2 // when it should have been -1, and no-one has noticed in the last 2+ years! // Changing the default of field questiondecimalpoints on table quiz to -1. $table = new xmldb_table('quiz'); $field = new xmldb_field('questiondecimalpoints', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '-1', 'decimalpoints'); // Launch change of default for field questiondecimalpoints. $dbman->change_field_default($table, $field); // Correct any wrong values. $DB->set_field('quiz', 'questiondecimalpoints', -1, array('questiondecimalpoints' => -2)); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2012061703, 'quiz'); } if ($oldversion < 2012100801) { // Define field timecheckstate to be added to quiz_attempts $table = new xmldb_table('quiz_attempts'); $field = new xmldb_field('timecheckstate', XMLDB_TYPE_INTEGER, '10', null, null, null, '0', 'timemodified'); // Conditionally launch add field timecheckstate if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Define index state-timecheckstate (not unique) to be added to quiz_attempts $table = new xmldb_table('quiz_attempts'); $index = new xmldb_index('state-timecheckstate', XMLDB_INDEX_NOTUNIQUE, array('state', 'timecheckstate')); // Conditionally launch add index state-timecheckstate if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Overdue cron no longer needs these unset_config('overduelastrun', 'quiz'); unset_config('overduedoneto', 'quiz'); // Update timecheckstate on all open attempts require_once($CFG->dirroot . '/mod/quiz/locallib.php'); quiz_update_open_attempts(array()); // quiz savepoint reached upgrade_mod_savepoint(true, 2012100801, 'quiz'); } // Moodle v2.4.0 release upgrade line // Put any upgrade step following this if ($oldversion < 2013031900) { // Quiz manual grading UI should be controlled by mod/quiz:grade, not :viewreports. $DB->set_field('quiz_reports', 'capability', 'mod/quiz:grade', array('name' => 'grading')); // Mod quiz savepoint reached. upgrade_mod_savepoint(true, 2013031900, 'quiz'); } // Moodle v2.5.0 release upgrade line. // Put any upgrade step following this. // Moodle v2.6.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014011300) { // Define key quiz (foreign) to be dropped form quiz_question_instances. $table = new xmldb_table('quiz_question_instances'); $key = new xmldb_key('quiz', XMLDB_KEY_FOREIGN, array('quiz'), 'quiz', array('id')); // Launch drop key quiz. $dbman->drop_key($table, $key); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014011300, 'quiz'); } if ($oldversion < 2014011301) { // Rename field quiz on table quiz_question_instances to quizid. $table = new xmldb_table('quiz_question_instances'); $field = new xmldb_field('quiz', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'id'); // Launch rename field quiz. $dbman->rename_field($table, $field, 'quizid'); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014011301, 'quiz'); } if ($oldversion < 2014011302) { // Define key quizid (foreign) to be added to quiz_question_instances. $table = new xmldb_table('quiz_question_instances'); $key = new xmldb_key('quizid', XMLDB_KEY_FOREIGN, array('quizid'), 'quiz', array('id')); // Launch add key quizid. $dbman->add_key($table, $key); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014011302, 'quiz'); } if ($oldversion < 2014011303) { // Define key question (foreign) to be dropped form quiz_question_instances. $table = new xmldb_table('quiz_question_instances'); $key = new xmldb_key('question', XMLDB_KEY_FOREIGN, array('question'), 'question', array('id')); // Launch drop key question. $dbman->drop_key($table, $key); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014011303, 'quiz'); } if ($oldversion < 2014011304) { // Rename field question on table quiz_question_instances to questionid. $table = new xmldb_table('quiz_question_instances'); $field = new xmldb_field('question', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'quiz'); // Launch rename field question. $dbman->rename_field($table, $field, 'questionid'); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014011304, 'quiz'); } if ($oldversion < 2014011305) { // Define key questionid (foreign) to be added to quiz_question_instances. $table = new xmldb_table('quiz_question_instances'); $key = new xmldb_key('questionid', XMLDB_KEY_FOREIGN, array('questionid'), 'question', array('id')); // Launch add key questionid. $dbman->add_key($table, $key); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014011305, 'quiz'); } if ($oldversion < 2014011306) { // Rename field grade on table quiz_question_instances to maxmark. $table = new xmldb_table('quiz_question_instances'); $field = new xmldb_field('grade', XMLDB_TYPE_NUMBER, '12, 7', null, XMLDB_NOTNULL, null, '0', 'question'); // Launch rename field grade. $dbman->rename_field($table, $field, 'maxmark'); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014011306, 'quiz'); } if ($oldversion < 2014021300) { // Define field needsupgradetonewqe to be dropped from quiz_attempts. $table = new xmldb_table('quiz_attempts'); $field = new xmldb_field('needsupgradetonewqe'); // Conditionally launch drop field needsupgradetonewqe. if ($dbman->field_exists($table, $field)) { $dbman->drop_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014021300, 'quiz'); } if ($oldversion < 2014022000) { // Define table quiz_question_instances to be renamed to quiz_slots. $table = new xmldb_table('quiz_question_instances'); // Launch rename table for quiz_question_instances. $dbman->rename_table($table, 'quiz_slots'); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022000, 'quiz'); } if ($oldversion < 2014022001) { // Define field slot to be added to quiz_slots. $table = new xmldb_table('quiz_slots'); $field = new xmldb_field('slot', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'id'); // Conditionally launch add field slot. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022001, 'quiz'); } if ($oldversion < 2014022002) { // Define field page to be added to quiz_slots. $table = new xmldb_table('quiz_slots'); $field = new xmldb_field('page', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'quizid'); // Conditionally launch add field page. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022002, 'quiz'); } if ($oldversion < 2014022003) { // Use the information in the old quiz.questions column to fill in the // new slot and page columns. $numquizzes = $DB->count_records('quiz'); if ($numquizzes > 0) { $pbar = new progress_bar('quizquestionstoslots', 500, true); $transaction = $DB->start_delegated_transaction(); $numberdone = 0; $quizzes = $DB->get_recordset('quiz', null, 'id', 'id,questions,sumgrades'); foreach ($quizzes as $quiz) { if ($quiz->questions === '') { $questionsinorder = array(); } else { $questionsinorder = explode(',', $quiz->questions); } $questionidtoslotrowid = $DB->get_records_menu('quiz_slots', array('quizid' => $quiz->id), '', 'id, questionid'); $problemfound = false; $currentpage = 1; $slot = 1; foreach ($questionsinorder as $questionid) { if ($questionid === '0') { // Page break. $currentpage++; continue; } if ($questionid === '') { // This can happen as the result of old restore bugs. // There can be a missing number in the list of ids. // All we can do about this is ignore it, which is what // the quiz system used to do. See MDL-45321. continue; } $key = array_search($questionid, $questionidtoslotrowid); if ($key !== false) { // Normal case. quiz_slots entry is present. // Just need to add slot and page. $quizslot = new stdClass(); $quizslot->id = $key; $quizslot->slot = $slot; $quizslot->page = $currentpage; $DB->update_record('quiz_slots', $quizslot); unset($questionidtoslotrowid[$key]); // So we can do a sanity check later. $slot++; continue; } else { // This should not happen. The question was listed in // quiz.questions, but there was not an entry for it in // quiz_slots (formerly quiz_question_instances). // Previously, if such question ids were found, then // starting an attempt at the quiz would throw an exception. // Here, we try to add the missing data. $problemfound = true; $defaultmark = $DB->get_field('question', 'defaultmark', array('id' => $questionid), IGNORE_MISSING); if ($defaultmark === false) { debugging('During upgrade, detected that question ' . $questionid . ' was listed as being part of quiz ' . $quiz->id . ' but this question no longer exists. Ignoring it.', DEBUG_NORMAL); // Non-existent question. Ignore it completely. continue; } debugging('During upgrade, detected that question ' . $questionid . ' was listed as being part of quiz ' . $quiz->id . ' but there was not entry for it in ' . 'quiz_question_instances/quiz_slots. Creating an entry with default mark.', DEBUG_NORMAL); $quizslot = new stdClass(); $quizslot->quizid = $quiz->id; $quizslot->slot = $slot; $quizslot->page = $currentpage; $quizslot->questionid = $questionid; $quizslot->maxmark = $defaultmark; $DB->insert_record('quiz_slots', $quizslot); $slot++; continue; } } // Now, as a sanity check, ensure we have done all the // quiz_slots rows linked to this quiz. if (!empty($questionidtoslotrowid)) { debugging('During upgrade, detected that questions ' . implode(', ', array_values($questionidtoslotrowid)) . ' had instances in quiz ' . $quiz->id . ' but were not actually used. ' . 'The instances have been removed.', DEBUG_NORMAL); $DB->delete_records_list('quiz_slots', 'id', array_keys($questionidtoslotrowid)); $problemfound = true; } // If there were problems found, we probably need to re-compute // quiz.sumgrades. if ($problemfound) { // C/f the quiz_update_sumgrades function in locallib.php, // but note that what we do here is a bit simpler. $newsumgrades = $DB->get_field_sql( "SELECT SUM(maxmark) FROM {quiz_slots} WHERE quizid = ?", array($quiz->id)); if (!$newsumgrades) { $newsumgrades = 0; } if (abs($newsumgrades - $quiz->sumgrades) > 0.000005) { debugging('Because of the previously mentioned problems, ' . 'sumgrades for quiz ' . $quiz->id . ' was changed from ' . $quiz->sumgrades . ' to ' . $newsumgrades . ' You should probably check that this quiz is still working: ' . $CFG->wwwroot . '/mod/quiz/view.php?q=' . $quiz->id . '.', DEBUG_NORMAL); $DB->set_field('quiz', 'sumgrades', $newsumgrades, array('id' => $quiz->id)); } } // Done with this quiz. Update progress bar. $numberdone++; $pbar->update($numberdone, $numquizzes, "Upgrading quiz structure - {$numberdone}/{$numquizzes}."); } $transaction->allow_commit(); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022003, 'quiz'); } if ($oldversion < 2014022004) { // If, for any reason, there were any quiz_slots missed, then try // to do something about that now before we add the NOT NULL constraints. // In fact, becuase of the sanity check at the end of the above check, // any such quiz_slots rows must refer to a non-existent quiz id, so // delete them. $DB->delete_records_select('quiz_slots', 'NOT EXISTS (SELECT 1 FROM {quiz} q WHERE q.id = quizid)'); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022004, 'quiz'); // Now, if any quiz_slots rows are left with slot or page NULL, something // is badly wrong. if ($DB->record_exists_select('quiz_slots', 'slot IS NULL OR page IS NULL')) { throw new coding_exception('Something went wrong in the quiz upgrade step for MDL-43749. ' . 'Some quiz_slots still contain NULLs which will break the NOT NULL constraints we need to add. ' . 'Please report this problem at http://tracker.moodle.org/ so that it can be investigated. Thank you.'); } } if ($oldversion < 2014022005) { // Changing nullability of field slot on table quiz_slots to not null. $table = new xmldb_table('quiz_slots'); $field = new xmldb_field('slot', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id'); // Launch change of nullability for field slot. $dbman->change_field_notnull($table, $field); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022005, 'quiz'); } if ($oldversion < 2014022006) { // Changing nullability of field page on table quiz_slots to not null. $table = new xmldb_table('quiz_slots'); $field = new xmldb_field('page', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'quizid'); // Launch change of nullability for field page. $dbman->change_field_notnull($table, $field); // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022006, 'quiz'); } if ($oldversion < 2014022007) { // Define index quizid-slot (unique) to be added to quiz_slots. $table = new xmldb_table('quiz_slots'); $index = new xmldb_index('quizid-slot', XMLDB_INDEX_UNIQUE, array('quizid', 'slot')); // Conditionally launch add index quizid-slot. if (!$dbman->index_exists($table, $index)) { $dbman->add_index($table, $index); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022007, 'quiz'); } if ($oldversion < 2014022008) { // Define field questions to be dropped from quiz. $table = new xmldb_table('quiz'); $field = new xmldb_field('questions'); // Conditionally launch drop field questions. if ($dbman->field_exists($table, $field)) { $dbman->drop_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014022008, 'quiz'); } // Moodle v2.7.0 release upgrade line. // Put any upgrade step following this. if ($oldversion < 2014052800) { // Define field completionattemptsexhausted to be added to quiz. $table = new xmldb_table('quiz'); $field = new xmldb_field('completionattemptsexhausted', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'showblocks'); // Conditionally launch add field completionattemptsexhausted. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014052800, 'quiz'); } if ($oldversion < 2014052801) { // Define field completionpass to be added to quiz. $table = new xmldb_table('quiz'); $field = new xmldb_field('completionpass', XMLDB_TYPE_INTEGER, '1', null, null, null, 0, 'completionattemptsexhausted'); // Conditionally launch add field completionpass. if (!$dbman->field_exists($table, $field)) { $dbman->add_field($table, $field); } // Quiz savepoint reached. upgrade_mod_savepoint(true, 2014052801, 'quiz'); } // Moodle v2.8.0 release upgrade line. // Put any upgrade step following this. return true; }