MDL-63497 mod_chat: Add support for removal of context users

This issue is part of the MDL-62560 Epic.
This commit is contained in:
Michael Hawkins 2018-09-10 18:00:59 +08:00 committed by David Monllao
parent 19fc6012cf
commit 464b17b79b
2 changed files with 174 additions and 0 deletions

View File

@ -33,9 +33,11 @@ use moodle_recordset;
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;
/**
@ -48,6 +50,7 @@ use core_privacy\local\request\writer;
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\plugin\provider {
/**
@ -123,6 +126,33 @@ 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;
}
$params = [
'instanceid' => $context->instanceid,
'modulename' => 'chat',
];
$sql = "SELECT chm.userid
FROM {course_modules} cm
JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
JOIN {chat} c ON c.id = cm.instance
JOIN {chat_messages} chm ON chm.chatid = c.id
WHERE cm.id = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
@ -225,6 +255,28 @@ class provider implements
$DB->delete_records_select('chat_users', $sql, $params);
}
/**
* 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();
$cm = $DB->get_record('course_modules', ['id' => $context->instanceid]);
$chat = $DB->get_record('chat', ['id' => $cm->instance]);
list($userinsql, $userinparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
$params = array_merge(['chatid' => $chat->id], $userinparams);
$sql = "chatid = :chatid AND userid {$userinsql}";
$DB->delete_records_select('chat_messages', $sql, $params);
$DB->delete_records_select('chat_messages_current', $sql, $params);
$DB->delete_records_select('chat_users', $sql, $params);
}
/**
* Return a dict of chat IDs mapped to their course module ID.
*

View File

@ -29,6 +29,7 @@ global $CFG;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use mod_chat\privacy\provider;
@ -96,6 +97,71 @@ class mod_chat_privacy_testcase extends provider_testcase {
$this->assertTrue(in_array(context_module::instance($chat2a->cmid)->id, $contextids));
}
/**
* Test that only users with relevant contexts are fetched.
*/
public function test_get_users_in_context() {
$component = 'mod_chat';
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$c2 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$chat1a = $dg->create_module('chat', ['course' => $c1]);
$chat1b = $dg->create_module('chat', ['course' => $c1]);
$chat2a = $dg->create_module('chat', ['course' => $c2]);
// Logins but no message.
$chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1a);
// Logins and messages.
$chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1b);
chat_send_chatmessage($chatuser, 'Hello world!');
// Silent login (no system message).
$chatuser = $this->login_user_in_course_chat($u1, $c2, $chat2a, 0, true);
// Silent login and messages.
$chatuser = $this->login_user_in_course_chat($u2, $c1, $chat1b, 0, true);
chat_send_chatmessage($chatuser, 'Ça va ?');
chat_send_chatmessage($chatuser, 'Moi, ça va.');
// Silent login and messages.
$chatuser = $this->login_user_in_course_chat($u2, $c2, $chat2a);
chat_send_chatmessage($chatuser, 'What\'s happening here?');
$context1a = context_module::instance($chat1a->cmid);
$context1b = context_module::instance($chat1b->cmid);
$context2a = context_module::instance($chat2a->cmid);
$userlist1a = new \core_privacy\local\request\userlist($context1a, $component);
$userlist1b = new \core_privacy\local\request\userlist($context1b, $component);
$userlist2a = new \core_privacy\local\request\userlist($context2a, $component);
\mod_chat\privacy\provider::get_users_in_context($userlist1a);
\mod_chat\privacy\provider::get_users_in_context($userlist1b);
\mod_chat\privacy\provider::get_users_in_context($userlist2a);
// Ensure correct users are found in relevant contexts.
$this->assertCount(1, $userlist1a);
$expected = [$u1->id];
$actual = $userlist1a->get_userids();
$this->assertEquals($expected, $actual);
$this->assertCount(2, $userlist1b);
$expected = [$u1->id, $u2->id];
$actual = $userlist1b->get_userids();
sort($expected);
sort($actual);
$this->assertEquals($expected, $actual);
$this->assertCount(1, $userlist2a);
$expected = [$u1->id];
$actual = $userlist1a->get_userids();
$this->assertEquals($expected, $actual);
}
public function test_delete_data_for_all_users_in_context() {
global $DB;
$dg = $this->getDataGenerator();
@ -190,6 +256,62 @@ class mod_chat_privacy_testcase extends provider_testcase {
$this->assert_has_no_data_in_chat($u2, $chat1b);
}
/**
* Test that data for users in approved userlist is deleted.
*/
public function test_delete_data_for_users() {
global $DB;
$component = 'mod_chat';
$dg = $this->getDataGenerator();
$c1 = $dg->create_course();
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$u3 = $dg->create_user();
$chat1 = $dg->create_module('chat', ['course' => $c1]);
$chat1context = context_module::instance($chat1->cmid);
$u1chat1 = $this->login_user_in_course_chat($u1, $c1, $chat1);
$u2chat1 = $this->login_user_in_course_chat($u2, $c1, $chat1);
$u3chat1 = $this->login_user_in_course_chat($u3, $c1, $chat1);
chat_send_chatmessage($u1chat1, 'Ça va ?');
chat_send_chatmessage($u2chat1, 'Oui, et toi ?');
chat_send_chatmessage($u1chat1, 'Bien merci.');
chat_send_chatmessage($u2chat1, 'Pourquoi ils disent omelette "du" fromage ?!');
chat_send_chatmessage($u1chat1, 'Aucune idée');
chat_send_chatmessage($u3chat1, 'Je ne comprends pas');
$this->assert_has_data_in_chat($u1, $chat1);
$this->assert_has_data_in_chat($u2, $chat1);
$this->assert_has_data_in_chat($u3, $chat1);
$chat2 = $dg->create_module('chat', ['course' => $c1]);
$u1chat2 = $this->login_user_in_course_chat($u1, $c1, $chat2);
$u2chat2 = $this->login_user_in_course_chat($u2, $c1, $chat2);
$u3chat2 = $this->login_user_in_course_chat($u3, $c1, $chat2);
chat_send_chatmessage($u1chat2, 'Why do we have a separate chat?');
chat_send_chatmessage($u2chat2, 'I have no idea!');
chat_send_chatmessage($u3chat2, 'Me either.');
$this->assert_has_data_in_chat($u1, $chat2);
$this->assert_has_data_in_chat($u2, $chat2);
$this->assert_has_data_in_chat($u3, $chat2);
// Delete user 1 and 2 data from chat 1 context only.
$approveduserids = [$u1->id, $u2->id];
$approvedlist = new approved_userlist($chat1context, $component, $approveduserids);
provider::delete_data_for_users($approvedlist);
// Ensure correct chat data is deleted.
$this->assert_has_no_data_in_chat($u1, $chat1);
$this->assert_has_no_data_in_chat($u2, $chat1);
$this->assert_has_data_in_chat($u3, $chat1);
$this->assert_has_data_in_chat($u1, $chat2);
$this->assert_has_data_in_chat($u2, $chat2);
$this->assert_has_data_in_chat($u3, $chat2);
}
public function test_export_data_for_user() {
global $DB;
$dg = $this->getDataGenerator();