mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
MDL-63497 mod_feedback: Add support for removal of context users
This issue is a part of the MDL-62560 Epic.
This commit is contained in:
parent
55d1ef377c
commit
e917288971
@ -31,9 +31,11 @@ use context_helper;
|
||||
use stdClass;
|
||||
use core_privacy\local\metadata\collection;
|
||||
use core_privacy\local\request\approved_contextlist;
|
||||
use core_privacy\local\request\approved_userlist;
|
||||
use core_privacy\local\request\contextlist;
|
||||
use core_privacy\local\request\helper;
|
||||
use core_privacy\local\request\transform;
|
||||
use core_privacy\local\request\userlist;
|
||||
use core_privacy\local\request\writer;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/feedback/lib.php');
|
||||
@ -48,6 +50,7 @@ require_once($CFG->dirroot . '/mod/feedback/lib.php');
|
||||
*/
|
||||
class provider implements
|
||||
\core_privacy\local\metadata\provider,
|
||||
\core_privacy\local\request\core_userlist_provider,
|
||||
\core_privacy\local\request\plugin\provider {
|
||||
|
||||
/**
|
||||
@ -102,6 +105,38 @@ class provider implements
|
||||
return $contextlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of users who have data within a context.
|
||||
*
|
||||
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
|
||||
*
|
||||
*/
|
||||
public static function get_users_in_context(userlist $userlist) {
|
||||
$context = $userlist->get_context();
|
||||
|
||||
if (!is_a($context, \context_module::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find users with feedback entries.
|
||||
$sql = "
|
||||
SELECT fc.userid
|
||||
FROM {%s} fc
|
||||
JOIN {modules} m
|
||||
ON m.name = :feedback
|
||||
JOIN {course_modules} cm
|
||||
ON cm.instance = fc.feedback
|
||||
AND cm.module = m.id
|
||||
JOIN {context} ctx
|
||||
ON ctx.instanceid = cm.id
|
||||
AND ctx.contextlevel = :modlevel
|
||||
WHERE ctx.id = :contextid";
|
||||
$params = ['feedback' => 'feedback', 'modlevel' => CONTEXT_MODULE, 'contextid' => $context->id];
|
||||
|
||||
$userlist->add_from_sql('userid', sprintf($sql, 'feedback_completed'), $params);
|
||||
$userlist->add_from_sql('userid', sprintf($sql, 'feedback_completedtmp'), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for the specified user, in the specified contexts.
|
||||
*
|
||||
@ -272,6 +307,48 @@ class provider implements
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple users within a single context.
|
||||
*
|
||||
* @param approved_userlist $userlist The approved context and user information to delete information for.
|
||||
*/
|
||||
public static function delete_data_for_users(approved_userlist $userlist) {
|
||||
global $DB;
|
||||
|
||||
$context = $userlist->get_context();
|
||||
$userids = $userlist->get_userids();
|
||||
|
||||
// Prepare SQL to gather all completed IDs.
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
|
||||
$completedsql = "
|
||||
SELECT fc.id
|
||||
FROM {%s} fc
|
||||
JOIN {modules} m
|
||||
ON m.name = :feedback
|
||||
JOIN {course_modules} cm
|
||||
ON cm.instance = fc.feedback
|
||||
AND cm.module = m.id
|
||||
WHERE cm.id = :instanceid
|
||||
AND fc.userid $insql";
|
||||
$completedparams = array_merge($inparams, ['instanceid' => $context->instanceid, 'feedback' => 'feedback']);
|
||||
|
||||
// Delete all submissions in progress.
|
||||
$completedtmpids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completedtmp'), $completedparams);
|
||||
if (!empty($completedtmpids)) {
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($completedtmpids, SQL_PARAMS_NAMED);
|
||||
$DB->delete_records_select('feedback_valuetmp', "completed $insql", $inparams);
|
||||
$DB->delete_records_select('feedback_completedtmp', "id $insql", $inparams);
|
||||
}
|
||||
|
||||
// Delete all final submissions.
|
||||
$completedids = $DB->get_fieldset_sql(sprintf($completedsql, 'feedback_completed'), $completedparams);
|
||||
if (!empty($completedids)) {
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($completedids, SQL_PARAMS_NAMED);
|
||||
$DB->delete_records_select('feedback_value', "completed $insql", $inparams);
|
||||
$DB->delete_records_select('feedback_completed', "id $insql", $inparams);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract an item record from a database record.
|
||||
*
|
||||
|
@ -115,6 +115,83 @@ class mod_feedback_privacy_testcase extends provider_testcase {
|
||||
$this->assertTrue(in_array(context_module::instance($cm2c->cmid)->id, $contextids));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting the users in a context.
|
||||
*/
|
||||
public function test_get_users_in_context() {
|
||||
global $DB;
|
||||
$dg = $this->getDataGenerator();
|
||||
$fg = $dg->get_plugin_generator('mod_feedback');
|
||||
$component = 'mod_feedback';
|
||||
|
||||
$c1 = $dg->create_course();
|
||||
$c2 = $dg->create_course();
|
||||
$cm0 = $dg->create_module('feedback', ['course' => SITEID]);
|
||||
$cm1a = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
|
||||
$cm1b = $dg->create_module('feedback', ['course' => $c1]);
|
||||
$cm2 = $dg->create_module('feedback', ['course' => $c2]);
|
||||
|
||||
$u1 = $dg->create_user();
|
||||
$u2 = $dg->create_user();
|
||||
|
||||
foreach ([$cm0, $cm1a, $cm1b, $cm2] as $feedback) {
|
||||
$i1 = $fg->create_item_numeric($feedback);
|
||||
$i2 = $fg->create_item_multichoice($feedback);
|
||||
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
|
||||
|
||||
if ($feedback == $cm1b) {
|
||||
$this->create_submission_with_answers($feedback, $u2, $answers);
|
||||
} else {
|
||||
$this->create_submission_with_answers($feedback, $u1, $answers);
|
||||
}
|
||||
}
|
||||
|
||||
// Unsaved submission for u2 in cm1a.
|
||||
$feedback = $cm1a;
|
||||
$i1 = $fg->create_item_numeric($feedback);
|
||||
$i2 = $fg->create_item_multichoice($feedback);
|
||||
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
|
||||
$this->create_tmp_submission_with_answers($feedback, $u2, $answers);
|
||||
|
||||
// Only u1 in cm0.
|
||||
$context = context_module::instance($cm0->cmid);
|
||||
$userlist = new \core_privacy\local\request\userlist($context, $component);
|
||||
provider::get_users_in_context($userlist);
|
||||
|
||||
$this->assertCount(1, $userlist);
|
||||
$this->assertEquals([$u1->id], $userlist->get_userids());
|
||||
|
||||
$context = context_module::instance($cm1a->cmid);
|
||||
$userlist = new \core_privacy\local\request\userlist($context, $component);
|
||||
provider::get_users_in_context($userlist);
|
||||
|
||||
// Two submissions in cm1a: saved for u1, unsaved for u2.
|
||||
$this->assertCount(2, $userlist);
|
||||
|
||||
$expected = [$u1->id, $u2->id];
|
||||
$actual = $userlist->get_userids();
|
||||
sort($expected);
|
||||
sort($actual);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
// Only u2 in cm1b.
|
||||
$context = context_module::instance($cm1b->cmid);
|
||||
$userlist = new \core_privacy\local\request\userlist($context, $component);
|
||||
provider::get_users_in_context($userlist);
|
||||
|
||||
$this->assertCount(1, $userlist);
|
||||
$this->assertEquals([$u2->id], $userlist->get_userids());
|
||||
|
||||
// Only u1 in cm2.
|
||||
$context = context_module::instance($cm2->cmid);
|
||||
$userlist = new \core_privacy\local\request\userlist($context, $component);
|
||||
provider::get_users_in_context($userlist);
|
||||
|
||||
$this->assertCount(1, $userlist);
|
||||
$this->assertEquals([$u1->id], $userlist->get_userids());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleting user data.
|
||||
*/
|
||||
@ -169,6 +246,66 @@ class mod_feedback_privacy_testcase extends provider_testcase {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleting data within a context for an approved userlist.
|
||||
*/
|
||||
public function test_delete_data_for_users() {
|
||||
global $DB;
|
||||
$dg = $this->getDataGenerator();
|
||||
$fg = $dg->get_plugin_generator('mod_feedback');
|
||||
|
||||
$c1 = $dg->create_course();
|
||||
$c2 = $dg->create_course();
|
||||
$cm0 = $dg->create_module('feedback', ['course' => SITEID]);
|
||||
$cm1 = $dg->create_module('feedback', ['course' => $c1, 'anonymous' => FEEDBACK_ANONYMOUS_NO]);
|
||||
$cm2 = $dg->create_module('feedback', ['course' => $c2]);
|
||||
$context0 = context_module::instance($cm0->cmid);
|
||||
$context1 = context_module::instance($cm1->cmid);
|
||||
|
||||
$u1 = $dg->create_user();
|
||||
$u2 = $dg->create_user();
|
||||
|
||||
// Create a bunch of data.
|
||||
foreach ([$cm0, $cm1, $cm2] as $feedback) {
|
||||
$i1 = $fg->create_item_numeric($feedback);
|
||||
$i2 = $fg->create_item_multichoice($feedback);
|
||||
$answers = ['numeric_' . $i1->id => '1', 'multichoice_' . $i2->id => [1]];
|
||||
|
||||
$this->create_submission_with_answers($feedback, $u1, $answers);
|
||||
$this->create_tmp_submission_with_answers($feedback, $u1, $answers);
|
||||
|
||||
$this->create_submission_with_answers($feedback, $u2, $answers);
|
||||
$this->create_tmp_submission_with_answers($feedback, $u2, $answers);
|
||||
}
|
||||
|
||||
// Delete u1 from cm0, ensure u2 data is retained.
|
||||
$approveduserlist = new core_privacy\local\request\approved_userlist($context0, 'mod_feedback', [$u1->id]);
|
||||
provider::delete_data_for_users($approveduserlist);
|
||||
|
||||
$this->assert_no_feedback_data_for_user($cm0, $u1);
|
||||
$this->assert_feedback_data_for_user($cm0, $u2);
|
||||
$this->assert_feedback_tmp_data_for_user($cm0, $u2);
|
||||
|
||||
// Ensure cm1 unaffected by cm1 deletes.
|
||||
$this->assert_feedback_data_for_user($cm1, $u1);
|
||||
$this->assert_feedback_tmp_data_for_user($cm1, $u1);
|
||||
$this->assert_feedback_data_for_user($cm1, $u2);
|
||||
$this->assert_feedback_tmp_data_for_user($cm1, $u2);
|
||||
|
||||
// Delete u1 and u2 from cm1, ensure no data is retained.
|
||||
$approveduserlist = new core_privacy\local\request\approved_userlist($context1, 'mod_feedback', [$u1->id, $u2->id]);
|
||||
provider::delete_data_for_users($approveduserlist);
|
||||
|
||||
$this->assert_no_feedback_data_for_user($cm1, $u1);
|
||||
$this->assert_no_feedback_data_for_user($cm1, $u2);
|
||||
|
||||
// Ensure cm2 is unaffected by any of the deletes.
|
||||
$this->assert_feedback_data_for_user($cm2, $u1);
|
||||
$this->assert_feedback_tmp_data_for_user($cm2, $u1);
|
||||
$this->assert_feedback_data_for_user($cm2, $u2);
|
||||
$this->assert_feedback_tmp_data_for_user($cm2, $u2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deleting a whole context.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user