MDL-78902 quiz restore: fix restore of 3.x backups with random questions
... where the random questions come from the quiz module context. Co-authored-by: Tim Hunt <[email protected]>
This commit is contained in:
committed by
Tim Hunt
co-authored by
Tim Hunt
parent
b621a7e4b3
commit
f119c5a3fe
@@ -5440,6 +5440,25 @@ class restore_move_module_questions_categories extends restore_execution_step {
|
||||
];
|
||||
$params += $categoryidparams;
|
||||
$DB->execute($sqlupdate, $params);
|
||||
|
||||
// As explained in {@see restore_quiz_activity_structure_step::process_quiz_question_legacy_instance()}
|
||||
// question_set_references relating to random questions restored from old backups,
|
||||
// which pick from context_module question_categores, will have been restored with the wrong questioncontextid.
|
||||
// So, now, we need to find those, and updated the questioncontextid.
|
||||
// We can only find them by picking apart the filter conditions, and seeign which categories they refer to.
|
||||
|
||||
// We need to check all the question_set_references belonging to this context_module.
|
||||
$references = $DB->get_records('question_set_references', ['usingcontextid' => $newcontext->newitemid]);
|
||||
foreach ($references as $reference) {
|
||||
$filtercondition = json_decode($reference->filtercondition);
|
||||
if (!empty($filtercondition->questioncategoryid) &&
|
||||
in_array($filtercondition->questioncategoryid, $categoryids)) {
|
||||
// This is one of ours, update the questionscontextid.
|
||||
$DB->set_field('question_set_references',
|
||||
'questionscontextid', $newcontext->newitemid,
|
||||
['id' => $reference->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now set the parent id for the question categories that were in the top category in the course context
|
||||
@@ -6245,6 +6264,11 @@ trait restore_question_set_reference_data_trait {
|
||||
|
||||
if ($context = $this->get_mappingid('context', $data->questionscontextid)) {
|
||||
$data->questionscontextid = $context;
|
||||
} else {
|
||||
$this->log('question_set_reference with old id ' . $data->id .
|
||||
' referenced question context ' . $data->questionscontextid .
|
||||
' which was not included in the backup. Therefore, this has been ' .
|
||||
' restored with the old questionscontextid.', backup::LOG_WARNING);
|
||||
}
|
||||
|
||||
$filtercondition['cat'] = implode(',', [
|
||||
|
||||
@@ -349,12 +349,17 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
|
||||
if ($question->qtype === 'random') {
|
||||
// Set reference data.
|
||||
$questionsetreference = new \stdClass();
|
||||
$questionsetreference = new stdClass();
|
||||
$questionsetreference->usingcontextid = context_module::instance(get_coursemodule_from_instance(
|
||||
"quiz", $module->id, $module->course)->id)->id;
|
||||
$questionsetreference->component = 'mod_quiz';
|
||||
$questionsetreference->questionarea = 'slot';
|
||||
$questionsetreference->itemid = $data->id;
|
||||
// If, in the orginal quiz that was backed up, this random question was pointing to a
|
||||
// category in the quiz question bank, then (for reasons explained in {@see restore_move_module_questions_categories})
|
||||
// right now, $question->questioncontextid will incorrectly point to the course contextid.
|
||||
// This will get fixed up later in restore_move_module_questions_categories
|
||||
// as part of moving the question categories to the right place.
|
||||
$questionsetreference->questionscontextid = $question->questioncontextid;
|
||||
$filtercondition = new stdClass();
|
||||
$filtercondition->questioncategoryid = $question->category;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace mod_quiz\backup;
|
||||
|
||||
use advanced_testcase;
|
||||
use backup;
|
||||
use restore_controller;
|
||||
|
||||
/**
|
||||
* Test restoring 3.9 backups including random questions.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @copyright 2024 Tomo Tsuyuki <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \restore_move_module_questions_categories
|
||||
*/
|
||||
final class restore_39_test extends advanced_testcase {
|
||||
|
||||
public function test_restore_random_question_39(): void {
|
||||
global $DB, $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// The example Moodle 3.9 backup file used in this test is an activity-level backup of a quiz.
|
||||
// So, the backup contains just the quiz-level question bank which contains:
|
||||
// | - Question category: Top
|
||||
// | - Question category: Default for Test MDL-78902 quiz
|
||||
// | - Question: Test MDL-78902 T/F question
|
||||
// | - Question: Random (Default for Test MDL-78902 quiz)
|
||||
// The quiz itself contains 1 question, the random question.
|
||||
// So, during the restore, the quiz_slot needs to be updated to use a question_set_reference.
|
||||
$backupfile = 'moodle_39_quiz_with_random_question_from_mod_context';
|
||||
|
||||
// Extract backup file.
|
||||
$backupid = $backupfile;
|
||||
$backuppath = make_backup_temp_directory($backupid);
|
||||
get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(
|
||||
__DIR__ . "/../fixtures/$backupfile.mbz", $backuppath);
|
||||
|
||||
// Restore the quiz activity in the backup from Moodle 3.9 to a new course.
|
||||
$coursecat = self::getDataGenerator()->create_category();
|
||||
$course = self::getDataGenerator()->create_course(['category' => $coursecat->id]);
|
||||
$rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $USER->id, backup::TARGET_EXISTING_ADDING);
|
||||
$this->assertTrue($rc->execute_precheck());
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
|
||||
// Get information about the quiz activity and confirm the references are correct.
|
||||
$modinfo = get_fast_modinfo($course->id);
|
||||
$quizzes = array_values($modinfo->get_instances_of('quiz'));
|
||||
// Get contextid for the restored quiz activity.
|
||||
$contextid = $quizzes[0]->context->id;
|
||||
$qcats = $DB->get_records('question_categories', ['contextid' => $contextid], 'parent');
|
||||
// Confirm there are 2 question categories for the restored quiz activity.
|
||||
$this->assertEquals(['top', 'Default for Test MDL-78902 quiz'], array_column($qcats, 'name'));
|
||||
// Get question_set_references records for the restored quiz activity.
|
||||
$references = $DB->get_records('question_set_references', ['usingcontextid' => $contextid]);
|
||||
foreach ($references as $reference) {
|
||||
$filtercondition = json_decode($reference->filtercondition);
|
||||
// Confirm the questionscontextid is set correctly, which is from filter question category id.
|
||||
$this->assertEquals($reference->questionscontextid,
|
||||
$qcats[$filtercondition->questioncategoryid]->contextid);
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
Reference in New Issue
Block a user