MDL-85701 mod_quiz: Move delete activities before questions.
Make sure the question is not used when activities has been deleted.
This commit is contained in:
@@ -746,6 +746,8 @@ function course_delete_module($cmid, $async = false) {
|
||||
"Cannot delete this module as the file mod/$modulename/lib.php is missing.");
|
||||
}
|
||||
|
||||
// Warning! there is very similar code in remove_course_contents.
|
||||
// If you are changing this code, you probably need to change that too.
|
||||
$deleteinstancefunction = $modulename . '_delete_instance';
|
||||
|
||||
// Ensure the delete_instance function exists for this module.
|
||||
@@ -774,6 +776,9 @@ function course_delete_module($cmid, $async = false) {
|
||||
"Cannot delete the module $modulename (instance).");
|
||||
}
|
||||
|
||||
// We delete the questions after the activity database is removed,
|
||||
// because questions are referenced via question reference tables
|
||||
// and cannot be deleted while the activities that use them still exist.
|
||||
question_delete_activity($cm);
|
||||
|
||||
// Remove all module files in case modules forget to do that.
|
||||
|
||||
+12
-10
@@ -4834,16 +4834,8 @@ function remove_course_contents($courseid, $showfeedback = true, ?array $options
|
||||
|
||||
if ($instances) {
|
||||
foreach ($instances as $cm) {
|
||||
if ($cm->id) {
|
||||
// Delete activity context questions and question categories.
|
||||
question_delete_activity($cm, coursedeletion: $coursedeletion);
|
||||
// Notify the competency subsystem.
|
||||
\core_competency\api::hook_course_module_deleted($cm);
|
||||
|
||||
// Delete all tag instances associated with the instance of this module.
|
||||
core_tag_tag::delete_instances("mod_{$modname}", null, context_module::instance($cm->id)->id);
|
||||
core_tag_tag::remove_all_item_tags('core', 'course_modules', $cm->id);
|
||||
}
|
||||
// Warning! there is very similar code in course_delete_module.
|
||||
// If you are changing this code, you probably need to change that too.
|
||||
if (function_exists($moddelete)) {
|
||||
// This purges all module data in related tables, extra user prefs, settings, etc.
|
||||
$moddelete($cm->modinstance);
|
||||
@@ -4854,6 +4846,16 @@ function remove_course_contents($courseid, $showfeedback = true, ?array $options
|
||||
}
|
||||
|
||||
if ($cm->id) {
|
||||
// Delete activity context questions and question categories.
|
||||
// We delete the questions after the activity database is removed,
|
||||
// because questions are referenced via question reference tables
|
||||
// and cannot be deleted while the activities that use them still exist.
|
||||
question_delete_activity($cm, coursedeletion: $coursedeletion);
|
||||
// Delete all tag instances associated with the instance of this module.
|
||||
core_tag_tag::delete_instances("mod_{$modname}", null, context_module::instance($cm->id)->id);
|
||||
core_tag_tag::remove_all_item_tags('core', 'course_modules', $cm->id);
|
||||
// Notify the competency subsystem.
|
||||
\core_competency\api::hook_course_module_deleted($cm);
|
||||
// Delete cm and its context - orphaned contexts are purged in cron in case of any race condition.
|
||||
context_helper::delete_instance(CONTEXT_MODULE, $cm->id);
|
||||
$DB->delete_records('course_modules_completion', ['coursemoduleid' => $cm->id]);
|
||||
|
||||
@@ -139,6 +139,47 @@ final class lib_test extends \advanced_testcase {
|
||||
$this->assertEquals(0, $DB->count_records('question_set_references', ['usingcontextid' => $context->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleting a quiz when the course is deleted.
|
||||
*
|
||||
* @covers ::quiz_delete_instance
|
||||
*/
|
||||
public function test_quiz_when_delete_course(): void {
|
||||
global $DB, $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Step 1: Create one course and a user with editing teacher capabilities.
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course();
|
||||
$teacher = $USER;
|
||||
$generator->enrol_user($teacher->id, $course->id, 'editingteacher');
|
||||
|
||||
// Create a quiz with questions in the first course.
|
||||
$quiz = $this->create_test_quiz($course);
|
||||
$context = \context_module::instance($quiz->cmid);
|
||||
// Create questions.
|
||||
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$cat = $questiongenerator->create_question_category(['contextid' => $context->id]);
|
||||
$saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
|
||||
|
||||
// Add to the quiz.
|
||||
quiz_add_quiz_question($saq->id, $quiz);
|
||||
// Delete the course.
|
||||
delete_course($course, false);
|
||||
|
||||
// Check that the question was deleted.
|
||||
$this->assertFalse($DB->record_exists('question', ['id' => $saq->id]));
|
||||
// Check that all the slots were removed.
|
||||
$this->assertFalse($DB->record_exists('quiz_slots', ['quizid' => $quiz->id]));
|
||||
// Check that the quiz was removed.
|
||||
$this->assertFalse($DB->record_exists('quiz', ['id' => $quiz->id]));
|
||||
// Check that any question references linked to this quiz are gone.
|
||||
$this->assertFalse($DB->record_exists('question_references', ['usingcontextid' => $context->id]));
|
||||
$this->assertFalse($DB->record_exists('question_set_references', ['usingcontextid' => $context->id]));
|
||||
}
|
||||
|
||||
public function test_quiz_get_user_attempts(): void {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
Reference in New Issue
Block a user