diff --git a/mod/quiz/classes/privacy/provider.php b/mod/quiz/classes/privacy/provider.php index 2e577d65139..9929590d767 100644 --- a/mod/quiz/classes/privacy/provider.php +++ b/mod/quiz/classes/privacy/provider.php @@ -133,6 +133,30 @@ class provider implements * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin. */ public static function get_contexts_for_userid(int $userid) : contextlist { + $resultset = new contextlist(); + + // Users who attempted the quiz. + $sql = "SELECT c.id + FROM {context} c + JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel + JOIN {modules} m ON m.id = cm.module AND m.name = :modname + JOIN {quiz} q ON q.id = cm.instance + JOIN {quiz_attempts} qa ON qa.quiz = q.id + WHERE qa.userid = :userid AND qa.preview = 0"; + $params = ['contextlevel' => CONTEXT_MODULE, 'modname' => 'quiz', 'userid' => $userid]; + $resultset->add_from_sql($sql, $params); + + // Users with quiz overrides. + $sql = "SELECT c.id + FROM {context} c + JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel + JOIN {modules} m ON m.id = cm.module AND m.name = :modname + JOIN {quiz} q ON q.id = cm.instance + JOIN {quiz_overrides} qo ON qo.quiz = q.id + WHERE qo.userid = :userid"; + $params = ['contextlevel' => CONTEXT_MODULE, 'modname' => 'quiz', 'userid' => $userid]; + $resultset->add_from_sql($sql, $params); + // Get the SQL used to link indirect question usages for the user. // This includes where a user is the manual marker on a question attempt. $qubaid = \core_question\privacy\provider::get_related_question_usages_for_user('rel', 'mod_quiz', 'qa.uniqueid', $userid); @@ -144,33 +168,16 @@ class provider implements JOIN {modules} m ON m.id = cm.module AND m.name = :modname JOIN {quiz} q ON q.id = cm.instance JOIN {quiz_attempts} qa ON qa.quiz = q.id - LEFT JOIN {quiz_overrides} qo ON qo.quiz = q.id AND qo.userid = :qouserid " . $qubaid->from . " - WHERE ( - qa.userid = :qauserid OR - " . $qubaid->where() . " OR - qo.id IS NOT NULL - ) AND qa.preview = 0 - "; - - $params = array_merge( - [ - 'contextlevel' => CONTEXT_MODULE, - 'modname' => 'quiz', - 'qauserid' => $userid, - 'qouserid' => $userid, - ], - $qubaid->from_where_params() - ); - - $resultset = new contextlist(); + WHERE " . $qubaid->where() . " AND qa.preview = 0"; + $params = ['contextlevel' => CONTEXT_MODULE, 'modname' => 'quiz'] + $qubaid->from_where_params(); $resultset->add_from_sql($sql, $params); return $resultset; } /** - * Delete all data for all users in the specified context. + * Export all user data for the specified user, in the specified contexts. * * @param approved_contextlist $contextlist The approved contexts to export information for. */ diff --git a/mod/quiz/tests/privacy_provider_test.php b/mod/quiz/tests/privacy_provider_test.php index 9e5ca4b7f32..9078dd3e542 100644 --- a/mod/quiz/tests/privacy_provider_test.php +++ b/mod/quiz/tests/privacy_provider_test.php @@ -56,6 +56,36 @@ class mod_quiz_privacy_provider_testcase extends \core_privacy\tests\provider_te $this->assertEmpty($contextlist); } + /** + * Test for provider::get_contexts_for_userid() when there is no quiz attempt at all. + */ + public function test_get_contexts_for_userid_no_attempt_with_override() { + global $DB; + $this->resetAfterTest(true); + + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + + // Make a quiz with an override. + $this->setUser(); + $quiz = $this->create_test_quiz($course); + $DB->insert_record('quiz_overrides', [ + 'quiz' => $quiz->id, + 'userid' => $user->id, + 'timeclose' => 1300, + 'timelimit' => null, + ]); + + $cm = get_coursemodule_from_instance('quiz', $quiz->id); + $context = \context_module::instance($cm->id); + + // Fetch the contexts - only one context should be returned. + $this->setUser(); + $contextlist = provider::get_contexts_for_userid($user->id); + $this->assertCount(1, $contextlist); + $this->assertEquals($context, $contextlist->current()); + } + /** * The export function should handle an empty contextlist properly. */