mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 21:49:15 +01:00
Merge branch 'MDL-84037_main' of https://github.com/marxjohnson/moodle
This commit is contained in:
commit
e33a3f8bee
@ -5482,8 +5482,25 @@ class restore_move_module_questions_categories extends restore_execution_step {
|
||||
foreach ($contexts as $contextid => $contextlevel) {
|
||||
if (!$newcontext = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'context', $contextid)) {
|
||||
// The bank for the question categories required by this module was not included in the backup,
|
||||
// but if that context still exists on the site then don't move them.
|
||||
if (context::instance_by_id($contextid, IGNORE_MISSING)) {
|
||||
// but if that context still exists on the site and the user has access then point question references
|
||||
// to the originals.
|
||||
$originalcontext = context::instance_by_id($contextid, IGNORE_MISSING);
|
||||
if ($originalcontext && has_capability('mod/qbank:view', $originalcontext)) {
|
||||
$originalquestions = get_questions_category(question_get_top_category($contextid), false);
|
||||
foreach ($originalquestions as $originalquestion) {
|
||||
$backupids = restore_dbops::get_backup_ids_record(
|
||||
$this->get_restoreid(),
|
||||
'question',
|
||||
$originalquestion->id,
|
||||
);
|
||||
$DB->set_field_select(
|
||||
'question_references',
|
||||
'questionbankentryid',
|
||||
$DB->get_field('question_versions', 'questionbankentryid', ['questionid' => $backupids->itemid]),
|
||||
'questionbankentryid = (SELECT questionbankentryid FROM {question_versions} WHERE questionid = ?)',
|
||||
[$backupids->newitemid],
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// We have no target question bank so create a default bank for categories without a module to attach to.
|
||||
@ -5588,6 +5605,20 @@ class restore_move_module_questions_categories extends restore_execution_step {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Remove any remaining course-level question categories from the restored course.
|
||||
$coursecatsql = "
|
||||
SELECT qc.id AS categoryid
|
||||
FROM {question_categories} qc
|
||||
JOIN {context} c ON c.id = qc.contextid
|
||||
WHERE c.contextlevel = :courselevel AND c.instanceid = :courseid
|
||||
";
|
||||
$DB->delete_records_subquery(
|
||||
'question_categories',
|
||||
'id',
|
||||
'categoryid',
|
||||
$coursecatsql,
|
||||
['courselevel' => context_course::LEVEL, 'courseid' => $this->task->get_courseid()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
namespace core_question;
|
||||
|
||||
use context_course;
|
||||
use mod_quiz\quiz_settings;
|
||||
use moodle_url;
|
||||
use question_bank;
|
||||
|
||||
@ -40,6 +41,7 @@ require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \restore_qtype_plugin
|
||||
* @covers \restore_create_categories_and_questions
|
||||
* @covers \restore_move_module_questions_categories
|
||||
*/
|
||||
final class backup_test extends \advanced_testcase {
|
||||
|
||||
@ -545,11 +547,9 @@ final class backup_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* If the backup contains ONLY a quiz but that quiz uses questions from a qbank module and itself,
|
||||
* and the original course does not exist on the target system,
|
||||
* then the non-quiz context categories and questions should restore to a default qbank module on the new course
|
||||
* if the old qbank no longer exists.
|
||||
*
|
||||
* @return void
|
||||
* @covers \restore_controller::execute_plan()
|
||||
*/
|
||||
public function test_quiz_activity_restore_to_new_course(): void {
|
||||
global $DB;
|
||||
@ -605,6 +605,117 @@ final class backup_test extends \advanced_testcase {
|
||||
$this->assertEquals('bank question', $bankq->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the backup contains ONLY a quiz but that quiz uses questions from a qbank module and itself,
|
||||
* and the original course does exist on the target system but you dont have permission to view the original qbank,
|
||||
* then the non-quiz context categories and questions should restore to a default qbank module on the new course
|
||||
* if the old qbank no longer exists.
|
||||
*/
|
||||
public function test_quiz_activity_restore_to_new_course_no_permission(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
self::setAdminUser();
|
||||
|
||||
// Create a course to make a backup.
|
||||
$data = $this->add_course_quiz_and_qbank();
|
||||
$oldquiz = $data->quiz;
|
||||
|
||||
// Backup ONLY the quiz module.
|
||||
$backupid = $this->backup_course_module($oldquiz->cmid);
|
||||
|
||||
// Create a new course to restore to.
|
||||
$newcourse = self::getDataGenerator()->create_course();
|
||||
$restoreuser = self::getDataGenerator()->create_user();
|
||||
self::getDataGenerator()->enrol_user($restoreuser->id, $newcourse->id, 'manager');
|
||||
$this->setUser($restoreuser);
|
||||
|
||||
$this->restore_to_course($backupid, $newcourse->id);
|
||||
$modinfo = get_fast_modinfo($newcourse);
|
||||
|
||||
// Assert we have our quiz including the category and question.
|
||||
$newquizzes = $modinfo->get_instances_of('quiz');
|
||||
$this->assertCount(1, $newquizzes);
|
||||
$newquiz = reset($newquizzes);
|
||||
$newquizcontext = \context_module::instance($newquiz->id);
|
||||
|
||||
$quizcats = $DB->get_records_select('question_categories',
|
||||
'parent <> 0 AND contextid = :contextid',
|
||||
['contextid' => $newquizcontext->id]
|
||||
);
|
||||
$this->assertCount(1, $quizcats);
|
||||
$quizcat = reset($quizcats);
|
||||
$quizcatqs = get_questions_category($quizcat, false);
|
||||
$this->assertCount(1, $quizcatqs);
|
||||
$quizq = reset($quizcatqs);
|
||||
$this->assertEquals('quiz question', $quizq->name);
|
||||
|
||||
// The backup did not contain the qbank that held the categories, but it is dependant.
|
||||
// So make sure the categories and questions got restored to a qbank module on the course.
|
||||
$defaultbanks = $modinfo->get_instances_of('qbank');
|
||||
$this->assertCount(1, $defaultbanks);
|
||||
$defaultbank = reset($defaultbanks);
|
||||
$defaultbankcontext = \context_module::instance($defaultbank->id);
|
||||
$bankcats = $DB->get_records_select('question_categories',
|
||||
'parent <> 0 AND contextid = :contextid',
|
||||
['contextid' => $defaultbankcontext->id]
|
||||
);
|
||||
$bankcat = reset($bankcats);
|
||||
$bankqs = get_questions_category($bankcat, false);
|
||||
$this->assertCount(1, $bankqs);
|
||||
$bankq = reset($bankqs);
|
||||
$this->assertEquals('bank question', $bankq->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the backup contains ONLY a quiz but that quiz uses questions from a qbank module and itself,
|
||||
* and that qbank still exists on the system, and the restoring user can access that qbank, then
|
||||
* the quiz should be restored with a copy of the quiz question, and a reference to the original qbank question.
|
||||
*/
|
||||
public function test_quiz_activity_restore_to_new_course_by_reference(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
self::setAdminUser();
|
||||
|
||||
// Create a course to make a backup.
|
||||
$data = $this->add_course_quiz_and_qbank();
|
||||
$oldquiz = $data->quiz;
|
||||
|
||||
// Backup ONLY the quiz module.
|
||||
$backupid = $this->backup_course_module($oldquiz->cmid);
|
||||
|
||||
// Create a new course to restore to.
|
||||
$newcourse = self::getDataGenerator()->create_course();
|
||||
|
||||
$this->restore_to_course($backupid, $newcourse->id);
|
||||
$modinfo = get_fast_modinfo($newcourse);
|
||||
|
||||
// Assert we have our new quiz with the expected questions.
|
||||
$newquizzes = $modinfo->get_instances_of('quiz');
|
||||
$this->assertCount(1, $newquizzes);
|
||||
/** @var \cm_info $newquiz */
|
||||
$newquiz = reset($newquizzes);
|
||||
$quiz = $DB->get_record('quiz', ['id' => $newquiz->instance], '*', MUST_EXIST);
|
||||
[$course, $cm] = get_course_and_cm_from_instance($quiz, 'quiz');
|
||||
$newquizsettings = new quiz_settings($quiz, $cm, $course);
|
||||
$newq1 = $newquizsettings->get_structure()->get_question_in_slot(1);
|
||||
$newq2 = $newquizsettings->get_structure()->get_question_in_slot(2);
|
||||
|
||||
$newquizcontext = \context_module::instance($newquiz->id);
|
||||
$qbankcontext = \context_module::instance($data->qbank->cmid);
|
||||
|
||||
// Check we've got a copy of the quiz question in the new context.
|
||||
$this->assertEquals($data->quizquestion->name, $newq2->name);
|
||||
$this->assertEquals($newquizcontext->id, $newq2->contextid);
|
||||
// Check we've got a reference to the qbank question in the original context.
|
||||
$this->assertEquals($data->qbankquestion->name, $newq1->name);
|
||||
$this->assertEquals($qbankcontext->id, $newq1->contextid);
|
||||
// Check we have the expected restored categories.
|
||||
$this->assertEquals(2, $DB->count_records('question_categories', ['stamp' => $data->quizcategory->stamp]));
|
||||
$this->assertEquals(1, $DB->count_records('question_categories', ['stamp' => $data->qbankcategory->stamp]));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the backup contains BOTH a quiz and a qbank module and the quiz uses questions from the qbank module and itself,
|
||||
* then we need to restore the categories and questions to the qbank and quiz modules included in the backup on the new course.
|
||||
|
Loading…
x
Reference in New Issue
Block a user