MDL-63712 core_message: Data should be in user context, not system
This issue is a part of the MDL-62560 Epic.
This commit is contained in:
committed by
Michael Hawkins
parent
4b681328f3
commit
734d9f403b
@@ -140,9 +140,25 @@ class provider implements
|
||||
* @return contextlist the list of contexts containing user info for the user.
|
||||
*/
|
||||
public static function get_contexts_for_userid(int $userid) : contextlist {
|
||||
// Messages are in the system context.
|
||||
global $DB;
|
||||
|
||||
$contextlist = new contextlist();
|
||||
$contextlist->add_system_context();
|
||||
|
||||
// Messages are in the user context.
|
||||
// For the sake of performance, there is no need to call add_from_sql for each of the bellow cases.
|
||||
// It is enough to add the user's context as soon as we come to the conclusion that the user has some data.
|
||||
// Also, the order of checking is sorted by the probability of occurrence (just by guess).
|
||||
|
||||
$hasdata = false;
|
||||
$hasdata = $hasdata || $DB->record_exists_select('message', 'useridfrom = ? OR ( notification = 1 AND useridto = ?)',
|
||||
[$userid, $userid]);
|
||||
$hasdata = $hasdata || $DB->record_exists_select('message_read', 'useridfrom = ? OR ( notification = 1 AND useridto = ?)',
|
||||
[$userid, $userid]);
|
||||
$hasdata = $hasdata || $DB->record_exists_select('message_contacts', 'userid = ? OR contactid = ?', [$userid, $userid]);
|
||||
|
||||
if ($hasdata) {
|
||||
$contextlist->add_user_context($userid);
|
||||
}
|
||||
|
||||
return $contextlist;
|
||||
}
|
||||
@@ -157,17 +173,17 @@ class provider implements
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove non-system contexts. If it ends up empty then early return.
|
||||
$contexts = array_filter($contextlist->get_contexts(), function($context) {
|
||||
return $context->contextlevel == CONTEXT_SYSTEM;
|
||||
$userid = $contextlist->get_user()->id;
|
||||
|
||||
// Remove non-user and invalid contexts. If it ends up empty then early return.
|
||||
$contexts = array_filter($contextlist->get_contexts(), function($context) use($userid) {
|
||||
return $context->contextlevel == CONTEXT_USER && $context->instanceid == $userid;
|
||||
});
|
||||
|
||||
if (empty($contexts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$userid = $contextlist->get_user()->id;
|
||||
|
||||
// Export the contacts.
|
||||
self::export_user_data_contacts($userid);
|
||||
|
||||
@@ -184,15 +200,9 @@ class provider implements
|
||||
* @param \context $context the context to delete in.
|
||||
*/
|
||||
public static function delete_data_for_all_users_in_context(\context $context) {
|
||||
global $DB;
|
||||
|
||||
if (!$context instanceof \context_system) {
|
||||
return;
|
||||
if ($context instanceof \context_user) {
|
||||
static::delete_user_data($context->instanceid);
|
||||
}
|
||||
|
||||
$DB->delete_records('message');
|
||||
$DB->delete_records('message_read');
|
||||
$DB->delete_records('message_contacts');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,22 +211,31 @@ class provider implements
|
||||
* @param approved_contextlist $contextlist a list of contexts approved for deletion.
|
||||
*/
|
||||
public static function delete_data_for_user(approved_contextlist $contextlist) {
|
||||
global $DB;
|
||||
|
||||
if (empty($contextlist->count())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove non-system contexts. If it ends up empty then early return.
|
||||
$contexts = array_filter($contextlist->get_contexts(), function($context) {
|
||||
return $context->contextlevel == CONTEXT_SYSTEM;
|
||||
$userid = $contextlist->get_user()->id;
|
||||
|
||||
// Remove non-user and invalid contexts. If it ends up empty then early return.
|
||||
$contexts = array_filter($contextlist->get_contexts(), function($context) use ($userid) {
|
||||
return $context->contextlevel == CONTEXT_USER && $context->instanceid == $userid;
|
||||
});
|
||||
|
||||
if (empty($contexts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$userid = $contextlist->get_user()->id;
|
||||
static::delete_user_data($userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all user data for the specified user.
|
||||
*
|
||||
* @param int $userid The user id
|
||||
*/
|
||||
protected static function delete_user_data(int $userid) {
|
||||
global $DB;
|
||||
|
||||
$DB->delete_records_select('message', 'useridfrom = ? AND notification = 0', [$userid]);
|
||||
$DB->delete_records_select('message_read', 'useridfrom = ? AND notification = 0', [$userid]);
|
||||
@@ -233,7 +252,7 @@ class provider implements
|
||||
protected static function export_user_data_contacts(int $userid) {
|
||||
global $DB;
|
||||
|
||||
$context = \context_system::instance();
|
||||
$context = \context_user::instance($userid);
|
||||
|
||||
// Get the user's contacts.
|
||||
if ($contacts = $DB->get_records('message_contacts', ['userid' => $userid], 'id ASC')) {
|
||||
@@ -256,7 +275,7 @@ class provider implements
|
||||
protected static function export_user_data_messages(int $userid) {
|
||||
global $DB;
|
||||
|
||||
$context = \context_system::instance();
|
||||
$context = \context_user::instance($userid);
|
||||
|
||||
$users = self::get_userids_in_conversation_with($userid);
|
||||
if (!empty($users)) {
|
||||
@@ -334,7 +353,7 @@ class provider implements
|
||||
protected static function export_user_data_notifications(int $userid) {
|
||||
global $DB;
|
||||
|
||||
$context = \context_system::instance();
|
||||
$context = \context_user::instance($userid);
|
||||
|
||||
$notificationdata = [];
|
||||
$sql = "SELECT id, useridfrom, useridto, subject, fullmessage, fullmessageformat,
|
||||
|
||||
@@ -159,16 +159,66 @@ class core_message_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::get_contexts_for_userid().
|
||||
* Test for provider::get_contexts_for_userid() when there is no message or notification.
|
||||
*/
|
||||
public function test_get_contexts_for_userid() {
|
||||
public function test_get_contexts_for_userid_no_data() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$contextlist = provider::get_contexts_for_userid($user->id);
|
||||
$this->assertEmpty($contextlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::get_contexts_for_userid() when there is a message between users.
|
||||
*/
|
||||
public function test_get_contexts_for_userid_with_message() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->create_message_or_notification($user1->id, $user2->id, time() - (9 * DAYSECS));
|
||||
|
||||
// Test for the sender.
|
||||
$contextlist = provider::get_contexts_for_userid($user1->id);
|
||||
$this->assertCount(1, $contextlist);
|
||||
$contextforuser = $contextlist->current();
|
||||
$this->assertEquals(SYSCONTEXTID, $contextforuser->id);
|
||||
$this->assertEquals(
|
||||
context_user::instance($user1->id)->id,
|
||||
$contextforuser->id);
|
||||
|
||||
// Test for the receiver.
|
||||
$contextlist = provider::get_contexts_for_userid($user2->id);
|
||||
$this->assertCount(0, $contextlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::get_contexts_for_userid() when there is a notification between users.
|
||||
*/
|
||||
public function test_get_contexts_for_userid_with_notification() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->create_message_or_notification($user1->id, $user2->id, time() - (9 * DAYSECS), true);
|
||||
|
||||
// Test for the sender.
|
||||
$contextlist = provider::get_contexts_for_userid($user1->id);
|
||||
$this->assertCount(1, $contextlist);
|
||||
$contextforuser = $contextlist->current();
|
||||
$this->assertEquals(
|
||||
context_user::instance($user1->id)->id,
|
||||
$contextforuser->id);
|
||||
|
||||
// Test for the receiver.
|
||||
$contextlist = provider::get_contexts_for_userid($user2->id);
|
||||
$this->assertCount(1, $contextlist);
|
||||
$contextforuser = $contextlist->current();
|
||||
$this->assertEquals(
|
||||
context_user::instance($user2->id)->id,
|
||||
$contextforuser->id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,9 +240,11 @@ class core_message_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
message_add_contact($user3->id, 0, $user1->id);
|
||||
message_add_contact($user4->id, 1, $user1->id);
|
||||
|
||||
$this->export_context_data_for_user($user1->id, \context_system::instance(), 'core_message');
|
||||
$user1context = context_user::instance($user1->id);
|
||||
|
||||
$writer = writer::with_context(\context_system::instance());
|
||||
$this->export_context_data_for_user($user1->id, $user1context, 'core_message');
|
||||
|
||||
$writer = writer::with_context($user1context);
|
||||
|
||||
$contacts = (array) $writer->get_data([get_string('contacts', 'core_message')]);
|
||||
usort($contacts, ['static', 'sort_contacts']);
|
||||
@@ -248,9 +300,11 @@ class core_message_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
message_delete_message($dbm2, $user1->id);
|
||||
message_delete_message($dbm5, $user1->id);
|
||||
|
||||
$this->export_context_data_for_user($user1->id, \context_system::instance(), 'core_message');
|
||||
$user1context = context_user::instance($user1->id);
|
||||
|
||||
$writer = writer::with_context(\context_system::instance());
|
||||
$this->export_context_data_for_user($user1->id, $user1context, 'core_message');
|
||||
|
||||
$writer = writer::with_context($user1context);
|
||||
|
||||
$this->assertTrue($writer->has_any_data());
|
||||
|
||||
@@ -344,9 +398,11 @@ class core_message_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
$this->create_message_or_notification($user2->id, $user3->id, $now + (2 * DAYSECS), true);
|
||||
$this->create_message_or_notification($user3->id, $user2->id, $now + (1 * DAYSECS), true);
|
||||
|
||||
$this->export_context_data_for_user($user1->id, \context_system::instance(), 'core_message');
|
||||
$user1context = context_user::instance($user1->id);
|
||||
|
||||
$writer = writer::with_context(\context_system::instance());
|
||||
$this->export_context_data_for_user($user1->id, $user1context, 'core_message');
|
||||
|
||||
$writer = writer::with_context($user1context);
|
||||
|
||||
$this->assertTrue($writer->has_any_data());
|
||||
|
||||
@@ -367,53 +423,77 @@ class core_message_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
// Create users to test with.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$now = time();
|
||||
$timeread = $now - DAYSECS;
|
||||
|
||||
$systemcontext = \context_system::instance();
|
||||
$user1context = context_user::instance($user1->id);
|
||||
|
||||
// Create contacts.
|
||||
message_add_contact($user1->id, 0, $user2->id);
|
||||
message_add_contact($user2->id, 0, $user1->id);
|
||||
message_add_contact($user2->id, 0, $user3->id);
|
||||
message_add_contact($user3->id, 0, $user2->id);
|
||||
|
||||
// Create messages.
|
||||
$m1 = $this->create_message_or_notification($user1->id, $user2->id, $now + (9 * DAYSECS), false, $timeread);
|
||||
$m2 = $this->create_message_or_notification($user2->id, $user1->id, $now + (8 * DAYSECS));
|
||||
$m3 = $this->create_message_or_notification($user2->id, $user1->id, $now + (7 * DAYSECS), false, $timeread);
|
||||
$m4 = $this->create_message_or_notification($user1->id, $user2->id, $now + (6 * DAYSECS));
|
||||
$m5 = $this->create_message_or_notification($user2->id, $user3->id, $now + (7 * DAYSECS));
|
||||
|
||||
// Create notifications.
|
||||
$n1 = $this->create_message_or_notification($user1->id, $user2->id, $now + (9 * DAYSECS), true, $timeread);
|
||||
$n2 = $this->create_message_or_notification($user2->id, $user1->id, $now + (8 * DAYSECS), true);
|
||||
$m3 = $this->create_message_or_notification($user2->id, $user1->id, $now + (7 * DAYSECS), true, $timeread);
|
||||
$m4 = $this->create_message_or_notification($user1->id, $user2->id, $now + (6 * DAYSECS), true);
|
||||
$n3 = $this->create_message_or_notification($user2->id, $user1->id, $now + (7 * DAYSECS), true, $timeread);
|
||||
$n4 = $this->create_message_or_notification($user1->id, $user2->id, $now + (6 * DAYSECS), true);
|
||||
$n5 = $this->create_message_or_notification($user2->id, $user3->id, $now + (7 * DAYSECS), true);
|
||||
|
||||
// Delete one of the messages.
|
||||
$dbm2 = $DB->get_record('message', ['id' => $m2]);
|
||||
message_delete_message($dbm2, $user1->id);
|
||||
|
||||
// There should be two contacts.
|
||||
$this->assertEquals(2, $DB->count_records('message_contacts'));
|
||||
// There should be 4 contacts.
|
||||
$this->assertEquals(4, $DB->count_records('message_contacts'));
|
||||
|
||||
// There should be two unread messages.
|
||||
$this->assertEquals(2, $DB->count_records('message', ['notification' => 0]));
|
||||
// There should be 3 unread messages.
|
||||
$this->assertEquals(3, $DB->count_records('message', ['notification' => 0]));
|
||||
|
||||
// There should be two read messages.
|
||||
$this->assertEquals(2, $DB->count_records('message_read', ['notification' => 0]));
|
||||
|
||||
// There should be two unread notifications.
|
||||
$this->assertEquals(2, $DB->count_records('message', ['notification' => 1]));
|
||||
// There should be 3 unread notifications.
|
||||
$this->assertEquals(3, $DB->count_records('message', ['notification' => 1]));
|
||||
|
||||
// There should be two read notifications.
|
||||
$this->assertEquals(2, $DB->count_records('message_read', ['notification' => 1]));
|
||||
|
||||
provider::delete_data_for_all_users_in_context($systemcontext);
|
||||
provider::delete_data_for_all_users_in_context($user1context);
|
||||
|
||||
// Confirm all has been deleted.
|
||||
$this->assertEquals(0, $DB->count_records('message_contacts'));
|
||||
$this->assertEquals(0, $DB->count_records('message'));
|
||||
$this->assertEquals(0, $DB->count_records('message_read'));
|
||||
// Confirm there are only 2 contacts left.
|
||||
$this->assertEquals(2, $DB->count_records('message_contacts'));
|
||||
// And none of them are not related to user1.
|
||||
$this->assertEquals(0,
|
||||
$DB->count_records_select('message_contacts', 'userid = ? OR contactid = ?', [$user1->id, $user1->id]));
|
||||
|
||||
// Confirm there are only 2 unread messages left.
|
||||
$this->assertEquals(2, $DB->count_records('message', ['notification' => 0]));
|
||||
// And none of them are from user1.
|
||||
$this->assertEquals(0, $DB->count_records('message', ['notification' => 0, 'useridfrom' => $user1->id]));
|
||||
|
||||
// Confirm there is only 1 read message left.
|
||||
$this->assertEquals(1, $DB->count_records('message_read', ['notification' => 0]));
|
||||
// And it is not from user1.
|
||||
$this->assertEquals(0, $DB->count_records('message_read', ['notification' => 0, 'useridfrom' => $user1->id]));
|
||||
|
||||
// Confirm there is only 1 unread notification left.
|
||||
$this->assertEquals(1, $DB->count_records('message', ['notification' => 1]));
|
||||
// And it is not from user1.
|
||||
$this->assertEquals(0, $DB->count_records('message', ['notification' => 1, 'useridfrom' => $user1->id]));
|
||||
|
||||
// Confirm there is no read notifications left.
|
||||
$this->assertEquals(0, $DB->count_records('message_read', ['notification' => 1]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,9 +548,9 @@ class core_message_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
// There should be two read notifications.
|
||||
$this->assertEquals(2, $DB->count_records('message_read', ['notification' => 1]));
|
||||
|
||||
$systemcontext = \context_system::instance();
|
||||
$user1context = context_user::instance($user1->id);
|
||||
$contextlist = new \core_privacy\local\request\approved_contextlist($user1, 'core_message',
|
||||
[$systemcontext->id]);
|
||||
[$user1context->id]);
|
||||
provider::delete_data_for_user($contextlist);
|
||||
|
||||
// Confirm the user 2 data still exists.
|
||||
|
||||
Reference in New Issue
Block a user