mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 21:49:15 +01:00
Merge branch 'MDL-75696_master' of https://github.com/marxjohnson/moodle
This commit is contained in:
commit
9f5d56b7c3
@ -119,18 +119,14 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Identify the backup we're dealing with.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
$backupbuild = 0;
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
if (!empty($matches[1])) {
|
||||
$backupbuild = (int) $matches[1]; // The date of Moodle build at the time of the backup.
|
||||
}
|
||||
$restoretask = $this->get_task();
|
||||
|
||||
// On older versions the freeze value has to be converted.
|
||||
// We do this from here as it is happening right before the file is read.
|
||||
// This only targets the backup files that can contain the legacy freeze.
|
||||
if ($backupbuild > 20150618 && (version_compare($backuprelease, '3.0', '<') || $backupbuild < 20160527)) {
|
||||
if ($restoretask->backup_version_compare(20150618, '>')
|
||||
&& $restoretask->backup_release_compare('3.0', '<')
|
||||
|| $restoretask->backup_version_compare(20160527, '<')) {
|
||||
$this->rewrite_step_backup_file_for_legacy_freeze($fullpath);
|
||||
}
|
||||
|
||||
@ -505,24 +501,25 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
protected function gradebook_calculation_freeze() {
|
||||
global $CFG;
|
||||
$gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $this->get_courseid());
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
$restoretask = $this->get_task();
|
||||
|
||||
// Extra credits need adjustments only for backups made between 2.8 release (20141110) and the fix release (20150619).
|
||||
if (!$gradebookcalculationsfreeze && $backupbuild >= 20141110 && $backupbuild < 20150619) {
|
||||
if (!$gradebookcalculationsfreeze && $restoretask->backup_version_compare(20141110, '>=')
|
||||
&& $restoretask->backup_version_compare(20150619, '<')) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_extra_credit_weightoverride($this->get_courseid());
|
||||
}
|
||||
// Calculated grade items need recalculating for backups made between 2.8 release (20141110) and the fix release (20150627).
|
||||
if (!$gradebookcalculationsfreeze && $backupbuild >= 20141110 && $backupbuild < 20150627) {
|
||||
if (!$gradebookcalculationsfreeze && $restoretask->backup_version_compare(20141110, '>=')
|
||||
&& $restoretask->backup_version_compare(20150627, '<')) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_calculated_grade_items($this->get_courseid());
|
||||
}
|
||||
// Courses from before 3.1 (20160518) may have a letter boundary problem and should be checked for this issue.
|
||||
// Backups from before and including 2.9 could have a build number that is greater than 20160518 and should
|
||||
// be checked for this problem.
|
||||
if (!$gradebookcalculationsfreeze && ($backupbuild < 20160518 || version_compare($backuprelease, '2.9', '<='))) {
|
||||
if (!$gradebookcalculationsfreeze
|
||||
&& ($restoretask->backup_version_compare(20160518, '<') || $restoretask->backup_release_compare('2.9', '<='))) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_course_letter_boundary($this->get_courseid());
|
||||
}
|
||||
@ -4868,13 +4865,8 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
protected function define_structure() {
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$before40 = false;
|
||||
if (version_compare($backuprelease, '4.0', '<') || $backupbuild < 20220202) {
|
||||
$before40 = true;
|
||||
}
|
||||
$restoretask = $this->get_task();
|
||||
$before40 = $restoretask->backup_release_compare('4.0', '<') || $restoretask->backup_version_compare(20220202, '<');
|
||||
// Start creating the path, category should be the first one.
|
||||
$paths = [];
|
||||
$paths [] = new restore_path_element('question_category', '/question_categories/question_category');
|
||||
@ -4956,13 +4948,8 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
|
||||
// Before 3.5, question categories could be created at top level.
|
||||
// From 3.5 onwards, all question categories should be a child of a special category called the "top" category.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$before35 = false;
|
||||
if (version_compare($backuprelease, '3.5', '<') || $backupbuild < 20180205) {
|
||||
$before35 = true;
|
||||
}
|
||||
$restoretask = $this->get_task();
|
||||
$before35 = $restoretask->backup_release_compare('3.5', '<') || $restoretask->backup_version_compare(20180205, '<');
|
||||
if (empty($mapping->info->parent) && $before35) {
|
||||
$top = question_get_top_category($data->contextid, true);
|
||||
$data->parent = $top->id;
|
||||
@ -5110,14 +5097,8 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
$oldid = $data->id;
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$before40 = false;
|
||||
if (version_compare($backuprelease, '4.0', '<') || $backupbuild < 20220202) {
|
||||
$before40 = true;
|
||||
}
|
||||
if ($before40) {
|
||||
$restoretask = $this->get_task();
|
||||
if ($restoretask->backup_release_compare('4.0', '<') || $restoretask->backup_version_compare(20220202, '<')) {
|
||||
// Check we have one mapping for this question.
|
||||
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
||||
return; // No mapping = this question doesn't need to be created/mapped.
|
||||
@ -5342,13 +5323,7 @@ class restore_move_module_questions_categories extends restore_execution_step {
|
||||
protected function define_execution() {
|
||||
global $DB;
|
||||
|
||||
$backuprelease = $this->task->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->task->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$after35 = false;
|
||||
if (version_compare($backuprelease, '3.5', '>=') && $backupbuild > 20180205) {
|
||||
$after35 = true;
|
||||
}
|
||||
$after35 = $this->task->backup_release_compare('3.5', '>=') && $this->task->backup_version_compare(20180205, '>');
|
||||
|
||||
$contexts = restore_dbops::restore_get_question_banks($this->get_restoreid(), CONTEXT_MODULE);
|
||||
foreach ($contexts as $contextid => $contextlevel) {
|
||||
|
@ -578,16 +578,11 @@ abstract class restore_dbops {
|
||||
CONTEXT_SYSTEM => CONTEXT_COURSE,
|
||||
CONTEXT_COURSECAT => CONTEXT_COURSE);
|
||||
|
||||
/** @var restore_controller $rc */
|
||||
$rc = restore_controller_dbops::load_controller($restoreid);
|
||||
$restoreinfo = $rc->get_info();
|
||||
$plan = $rc->get_plan();
|
||||
$after35 = $plan->backup_release_compare('3.5', '>=') && $plan->backup_version_compare(20180205, '>');
|
||||
$rc->destroy(); // Always need to destroy.
|
||||
$backuprelease = $restoreinfo->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $restoreinfo->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$after35 = false;
|
||||
if (version_compare($backuprelease, '3.5', '>=') && $backupbuild > 20180205) {
|
||||
$after35 = true;
|
||||
}
|
||||
|
||||
// For any contextlevel, follow this process logic:
|
||||
//
|
||||
|
@ -212,6 +212,30 @@ class restore_plan extends base_plan implements loggable {
|
||||
}
|
||||
$progress->end_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle version with the one the backup was taken from.
|
||||
*
|
||||
* @param int $version Moodle version number (YYYYMMDD or YYYYMMDDXX)
|
||||
* @param string $operator Operator to compare the provided version to the backup version. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_version_compare(int $version, string $operator): bool {
|
||||
preg_match('/(\d{' . strlen($version) . '})/', $this->get_info()->moodle_version, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
return version_compare($backupbuild, $version, $operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle release with the one the backup was taken from.
|
||||
*
|
||||
* @param string $release Moodle release (X.Y or X.Y.Z)
|
||||
* @param string $operator Operator to compare the provided release to the backup release. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_release_compare(string $release, string $operator): bool {
|
||||
return version_compare($this->get_info()->backup_release, $release, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -124,6 +124,28 @@ abstract class restore_task extends base_task {
|
||||
$this->after_restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle version with the one the backup was taken from.
|
||||
*
|
||||
* @param int $version Moodle version number (YYYYMMDD or YYYYMMDDXX)
|
||||
* @param string $operator Operator to compare the provided version to the backup version. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_version_compare(int $version, string $operator) {
|
||||
return $this->plan->backup_version_compare($version, $operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle release with the one the backup was taken from.
|
||||
*
|
||||
* @param string $release Moodle release (X.Y or X.Y.Z)
|
||||
* @param string $operator Operator to compare the provided release to the backup release. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_release_compare(string $release, string $operator) {
|
||||
return $this->plan->backup_release_compare($release, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -45,6 +45,11 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
/** @var stdClass */
|
||||
protected $oldquizlayout;
|
||||
|
||||
/**
|
||||
* @var array Track old question ids that need to be removed at the end of the restore.
|
||||
*/
|
||||
protected $oldquestionids = [];
|
||||
|
||||
protected function define_structure() {
|
||||
|
||||
$paths = [];
|
||||
@ -352,11 +357,10 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
$questionsetreference->questionscontextid = $question->questioncontextid;
|
||||
$filtercondition = new stdClass();
|
||||
$filtercondition->questioncategoryid = $question->category;
|
||||
$filtercondition->includingsubcategories = $data->includingsubcategories;
|
||||
$filtercondition->includingsubcategories = $data->includingsubcategories ?? false;
|
||||
$questionsetreference->filtercondition = json_encode($filtercondition);
|
||||
$DB->insert_record('question_set_references', $questionsetreference);
|
||||
// Cleanup leftover random qtype data from question table.
|
||||
question_delete_question($question->questionid);
|
||||
$this->oldquestionids[$question->questionid] = 1;
|
||||
} else {
|
||||
// Reference data.
|
||||
$questionreference = new \stdClass();
|
||||
@ -617,4 +621,12 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
'shufflequestions' => $this->legacyshufflequestionsoption]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function after_restore() {
|
||||
parent::after_restore();
|
||||
// Delete old random questions that have been converted to set references.
|
||||
foreach (array_keys($this->oldquestionids) as $oldquestionid) {
|
||||
question_delete_question($oldquestionid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
mod/quiz/tests/fixtures/pre-40-shared-random-question.mbz
vendored
Normal file
BIN
mod/quiz/tests/fixtures/pre-40-shared-random-question.mbz
vendored
Normal file
Binary file not shown.
@ -380,6 +380,59 @@ class quiz_question_restore_test extends \advanced_testcase {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test pre 4.0 quiz restore for random question used on multiple quizzes.
|
||||
*
|
||||
* @covers ::process_quiz_question_legacy_instance
|
||||
*/
|
||||
public function test_pre_4_quiz_restore_shared_random_question() {
|
||||
global $USER, $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$backupid = 'abc';
|
||||
$backuppath = make_backup_temp_directory($backupid);
|
||||
get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(
|
||||
__DIR__ . "/fixtures/pre-40-shared-random-question.mbz", $backuppath);
|
||||
|
||||
// Do the restore to new course with default settings.
|
||||
$categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
|
||||
$newcourseid = \restore_dbops::create_new_course('Test fullname', 'Test shortname', $categoryid);
|
||||
$rc = new \restore_controller($backupid, $newcourseid, \backup::INTERACTIVE_NO, \backup::MODE_GENERAL, $USER->id,
|
||||
\backup::TARGET_NEW_COURSE);
|
||||
|
||||
$this->assertTrue($rc->execute_precheck());
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
|
||||
// Get the information about the resulting course and check that it is set up correctly.
|
||||
// Each quiz should contain an instance of the random question.
|
||||
$modinfo = get_fast_modinfo($newcourseid);
|
||||
$quizzes = $modinfo->get_instances_of('quiz');
|
||||
$this->assertCount(2, $quizzes);
|
||||
foreach ($quizzes as $quiz) {
|
||||
$quizobj = \mod_quiz\quiz_settings::create($quiz->instance);
|
||||
$structure = structure::create_for_quiz($quizobj);
|
||||
|
||||
// Are the correct slots returned?
|
||||
$slots = $structure->get_slots();
|
||||
$this->assertCount(1, $slots);
|
||||
|
||||
$quizobj->preload_questions();
|
||||
$quizobj->load_questions();
|
||||
$questions = $quizobj->get_questions();
|
||||
$this->assertCount(1, $questions);
|
||||
}
|
||||
|
||||
// Count the questions for course question bank.
|
||||
// We should have a single question, the random question should have been deleted after the restore.
|
||||
$this->assertEquals(1, $this->question_count(\context_course::instance($newcourseid)->id));
|
||||
$this->assertEquals(1, $this->question_count(\context_course::instance($newcourseid)->id,
|
||||
"AND q.qtype <> 'random'"));
|
||||
|
||||
// Count the questions in quiz qbank.
|
||||
$this->assertEquals(0, $this->question_count($quizobj->get_context()->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that question slots are correctly backed up and restored with all properties.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user