Merge branch 'MDL-61919_34' of git://github.com/markn86/moodle into MOODLE_34_STABLE

This commit is contained in:
Andrew Nicols 2018-05-07 15:46:46 +08:00
commit 26fad064f0
3 changed files with 986 additions and 0 deletions

View file

@ -95,6 +95,29 @@ $string['outputenabled'] = 'Output enabled';
$string['outputnotavailable'] = 'Not available'; $string['outputnotavailable'] = 'Not available';
$string['outputnotconfigured'] = 'Not configured'; $string['outputnotconfigured'] = 'Not configured';
$string['permitted'] = 'Permitted'; $string['permitted'] = 'Permitted';
$string['privacy:metadata:messages'] = 'Message/notifications';
$string['privacy:metadata:messages:component'] = 'The component responsible for sending the message/notification';
$string['privacy:metadata:messages:contexturl'] = 'The URL related to a notification';
$string['privacy:metadata:messages:contexturlname'] = 'The name of the context';
$string['privacy:metadata:messages:eventtype'] = 'The event type';
$string['privacy:metadata:messages:fullmessage'] = 'The full message/notification';
$string['privacy:metadata:messages:fullmessageformat'] = 'The message/notification format';
$string['privacy:metadata:messages:fullmessagehtml'] = 'The HTML of the message/notification';
$string['privacy:metadata:messages:notification'] = 'Flag whether or not this is a notification';
$string['privacy:metadata:messages:smallmessage'] = 'The small message/notification';
$string['privacy:metadata:messages:subject'] = 'The subject of the message/notification';
$string['privacy:metadata:messages:timecreated'] = 'The date at which the message/notification was created';
$string['privacy:metadata:messages:timeread'] = 'The date at which the message/notification was read';
$string['privacy:metadata:messages:timeuserfromdeleted'] = 'The date at which the message/notification was deleted by the sender';
$string['privacy:metadata:messages:timeusertodeleted'] = 'The date at which the message/notification was deleted by the receiver';
$string['privacy:metadata:messages:useridfrom'] = 'The ID of the user who sent the notification';
$string['privacy:metadata:messages:useridto'] = 'The ID of the user who received the notification';
$string['privacy:metadata:message_contacts'] = 'The list of contacts';
$string['privacy:metadata:message_contacts:blocked'] = 'Flag whether or not the user is blocked';
$string['privacy:metadata:message_contacts:contactid'] = 'The ID of the user who is a contact';
$string['privacy:metadata:message_contacts:userid'] = 'The ID of the user whose contact list we are viewing';
$string['privacy:metadata:preference:core_message_settings'] = 'Settings related to messaging';
$string['privacy:request:preference:set'] = 'The value of the setting \'{$a->name}\' was \'{$a->value}\'';
$string['processorsettings'] = 'Processor settings'; $string['processorsettings'] = 'Processor settings';
$string['removecontact'] = 'Remove contact'; $string['removecontact'] = 'Remove contact';
$string['removecoursefilter'] = 'Remove filter for course {$a}'; $string['removecoursefilter'] = 'Remove filter for course {$a}';
@ -126,6 +149,7 @@ $string['togglenotificationmenu'] = 'Toggle notifications menu';
$string['togglemessagemenu'] = 'Toggle messages menu'; $string['togglemessagemenu'] = 'Toggle messages menu';
$string['touserdoesntexist'] = 'You can not send a message to a user id ({$a}) that doesn\'t exist'; $string['touserdoesntexist'] = 'You can not send a message to a user id ({$a}) that doesn\'t exist';
$string['unblockcontact'] = 'Unblock contact'; $string['unblockcontact'] = 'Unblock contact';
$string['unknownuser'] = 'Unknown user';
$string['unreadnotification'] = 'Unread notification: {$a}'; $string['unreadnotification'] = 'Unread notification: {$a}';
$string['unreadnewmessage'] = 'New message from {$a}'; $string['unreadnewmessage'] = 'New message from {$a}';
$string['userisblockingyou'] = 'This user has blocked you from sending messages to them'; $string['userisblockingyou'] = 'This user has blocked you from sending messages to them';

View file

@ -0,0 +1,409 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for core_message.
*
* @package core_message
* @copyright 2018 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_message\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem implementation for core_message.
*
* @copyright 2018 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\subsystem\provider,
\core_privacy\local\request\user_preference_provider {
/**
* Return the fields which contain personal data.
*
* @param collection $items a reference to the collection to use to store the metadata.
* @return collection the updated collection of metadata items.
*/
public static function get_metadata(collection $items) : collection {
$items->add_database_table(
'message',
[
'useridfrom' => 'privacy:metadata:messages:useridfrom',
'useridto' => 'privacy:metadata:messages:useridto',
'subject' => 'privacy:metadata:messages:subject',
'fullmessage' => 'privacy:metadata:messages:fullmessage',
'fullmessageformat' => 'privacy:metadata:messages:fullmessageformat',
'fullmessagehtml' => 'privacy:metadata:messages:fullmessagehtml',
'smallmessage' => 'privacy:metadata:messages:smallmessage',
'notification' => 'privacy:metadata:messages:notification',
'contexturl' => 'privacy:metadata:messages:contexturl',
'contexturlname' => 'privacy:metadata:messages:contexturlname',
'component' => 'privacy:metadata:messages:component',
'eventtype' => 'privacy:metadata:messages:eventtype',
'timecreated' => 'privacy:metadata:messages:timecreated',
'timeuserfromdeleted' => 'privacy:metadata:messages:timeuserfromdeleted',
'timeusertodeleted' => 'privacy:metadata:messages:timeusertodeleted'
],
'privacy:metadata:messages'
);
$items->add_database_table(
'message_read',
[
'useridfrom' => 'privacy:metadata:messages:useridfrom',
'useridto' => 'privacy:metadata:messages:useridto',
'subject' => 'privacy:metadata:messages:subject',
'fullmessage' => 'privacy:metadata:messages:fullmessage',
'fullmessageformat' => 'privacy:metadata:messages:fullmessageformat',
'fullmessagehtml' => 'privacy:metadata:messages:fullmessagehtml',
'smallmessage' => 'privacy:metadata:messages:smallmessage',
'notification' => 'privacy:metadata:messages:notification',
'contexturl' => 'privacy:metadata:messages:contexturl',
'contexturlname' => 'privacy:metadata:messages:contexturlname',
'component' => 'privacy:metadata:messages:component',
'eventtype' => 'privacy:metadata:messages:eventtype',
'timecreated' => 'privacy:metadata:messages:timecreated',
'timeread' => 'privacy:metadata:messages:timeread',
'timeuserfromdeleted' => 'privacy:metadata:messages:timeuserfromdeleted',
'timeusertodeleted' => 'privacy:metadata:messages:timeusertodeleted'
],
'privacy:metadata:messages'
);
$items->add_database_table(
'message_contacts',
[
'userid' => 'privacy:metadata:message_contacts:userid',
'contactid' => 'privacy:metadata:message_contacts:contactid',
'blocked' => 'privacy:metadata:message_contacts:blocked',
],
'privacy:metadata:message_contacts'
);
// Now add that we also have user preferences.
$items->add_user_preference('core_message_messageprovider_settings',
'privacy:metadata:preference:core_message_settings');
return $items;
}
/**
* Store all user preferences for core message.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$preferences = get_user_preferences(null, null, $userid);
foreach ($preferences as $name => $value) {
if ((substr($name, 0, 16) == 'message_provider') || ($name == 'message_blocknoncontacts')) {
writer::export_user_preference(
'core_message',
$name,
$value,
get_string('privacy:request:preference:set', 'core_message', (object) [
'name' => $name,
'value' => $value,
])
);
}
}
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid the userid.
* @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.
$contextlist = new contextlist();
$contextlist->add_system_context();
return $contextlist;
}
/**
* Export personal data for the given approved_contextlist. User and context information is contained within the contextlist.
*
* @param approved_contextlist $contextlist a list of contexts approved for export.
*/
public static function export_user_data(approved_contextlist $contextlist) {
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;
});
if (empty($contexts)) {
return;
}
$userid = $contextlist->get_user()->id;
// Export the contacts.
self::export_user_data_contacts($userid);
// Export the notifications.
self::export_user_data_notifications($userid);
// Export the messages, with any related actions.
self::export_user_data_messages($userid);
}
/**
* Delete all data for all users in the specified context.
*
* @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;
}
$DB->delete_records('message');
$DB->delete_records('message_read');
$DB->delete_records('message_contacts');
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @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;
});
if (empty($contexts)) {
return;
}
$userid = $contextlist->get_user()->id;
$DB->delete_records_select('message', 'useridfrom = ? AND notification = 0', [$userid]);
$DB->delete_records_select('message_read', 'useridfrom = ? AND notification = 0', [$userid]);
$DB->delete_records_select('message', '(useridfrom = ? OR useridto = ?) AND notification = 1', [$userid, $userid]);
$DB->delete_records_select('message_read', '(useridfrom = ? OR useridto = ?) AND notification = 1', [$userid, $userid]);
$DB->delete_records_select('message_contacts', 'userid = ? OR contactid = ?', [$userid, $userid]);
}
/**
* Export the messaging contact data.
*
* @param int $userid
*/
protected static function export_user_data_contacts(int $userid) {
global $DB;
$context = \context_system::instance();
// Get the user's contacts.
if ($contacts = $DB->get_records('message_contacts', ['userid' => $userid], 'id ASC')) {
$contactdata = [];
foreach ($contacts as $contact) {
$contactdata[] = (object) [
'contact' => transform::user($contact->contactid),
'blocked' => transform::yesno($contact->blocked)
];
}
writer::with_context($context)->export_data([get_string('contacts', 'core_message')], (object) $contactdata);
}
}
/**
* Export the messaging data.
*
* @param int $userid
*/
protected static function export_user_data_messages(int $userid) {
global $DB;
$context = \context_system::instance();
$users = self::get_userids_in_conversation_with($userid);
if (!empty($users)) {
// Ok, let's get the other users details. Note - the user may no longer exist.
$userids = array_keys($users);
list($useridsql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$userfields = \user_picture::fields('u');
$userssql = "SELECT $userfields
FROM {user} u
WHERE u.id $useridsql
AND u.deleted = 0";
$otherusers = $DB->get_records_sql($userssql, $userparams + ['userid' => $userid]);
foreach ($users as $user) {
$otheruserfullname = get_string('unknownuser', 'core_message');
// It's possible the other user may have been deleted.
if (isset($otherusers[$user->id])) {
$otheruserfullname = fullname($otherusers[$user->id]);
}
$sql = "SELECT id, useridfrom, useridto, subject, fullmessage, fullmessageformat,
fullmessagehtml, smallmessage, notification, contexturl,
contexturlname, timecreated, timeuserfromdeleted, timeusertodeleted,
component, eventtype, 0 as timeread
FROM {message} m
WHERE notification = 0
AND (useridfrom = ? AND useridto = ?) OR (useridfrom = ? AND useridto = ?)
UNION ALL
SELECT id, useridfrom, useridto, subject, fullmessage, fullmessageformat,
fullmessagehtml, smallmessage, notification, contexturl,
contexturlname, timecreated, timeuserfromdeleted, timeusertodeleted,
component, eventtype, timeread
FROM {message_read} mr
WHERE notification = 0
AND (useridfrom = ? AND useridto = ?) OR (useridfrom = ? AND useridto = ?)
ORDER BY timecreated ASC";
$params = [$userid, $user->id, $user->id, $userid, $userid, $user->id, $user->id, $userid];
$messages = $DB->get_recordset_sql($sql, $params);
$messagedata = [];
foreach ($messages as $message) {
$timeread = !empty($message->timeread) ? transform::datetime($message->timeread) : '-';
$issender = $userid == $message->useridfrom;
$timedeletedfield = 'timeusertodeleted';
if ($issender) {
$timedeletedfield = 'timeuserfromdeleted';
}
$data = [
'sender' => transform::yesno($issender),
'message' => message_format_message_text($message),
'timecreated' => transform::datetime($message->timecreated),
'timeread' => $timeread
];
if (!empty($message->$timedeletedfield)) {
$data['timedeleted'] = transform::datetime($message->$timedeletedfield);
}
$messagedata[] = (object) $data;
}
$messages->close();
writer::with_context($context)->export_data([get_string('messages', 'core_message'), $otheruserfullname],
(object) $messagedata);
}
}
}
/**
* Export the notification data.
*
* @param int $userid
*/
protected static function export_user_data_notifications(int $userid) {
global $DB;
$context = \context_system::instance();
$notificationdata = [];
$sql = "SELECT id, useridfrom, useridto, subject, fullmessage, fullmessageformat,
fullmessagehtml, smallmessage, notification, contexturl,
contexturlname, timecreated, timeuserfromdeleted, timeusertodeleted,
component, eventtype, 0 as timeread
FROM {message} m
WHERE notification = 1 AND useridfrom = ? OR useridto = ?
UNION ALL
SELECT id, useridfrom, useridto, subject, fullmessage, fullmessageformat,
fullmessagehtml, smallmessage, notification, contexturl,
contexturlname, timecreated, timeuserfromdeleted, timeusertodeleted,
component, eventtype, timeread
FROM {message_read} mr
WHERE notification = 1 AND useridfrom = ? OR useridto = ?
ORDER BY timecreated DESC";
$notifications = $DB->get_recordset_sql($sql, [$userid, $userid, $userid, $userid]);
foreach ($notifications as $notification) {
$timeread = !empty($notification->timeread) ? transform::datetime($notification->timeread) : '-';
$data = (object) [
'subject' => $notification->subject,
'fullmessage' => $notification->fullmessage,
'smallmessage' => $notification->smallmessage,
'component' => $notification->component,
'eventtype' => $notification->eventtype,
'contexturl' => $notification->contexturl,
'contexturlname' => $notification->contexturlname,
'timeread' => $timeread,
'timecreated' => transform::datetime($notification->timecreated)
];
$notificationdata[] = $data;
}
$notifications->close();
writer::with_context($context)->export_data([get_string('notifications', 'core_message')], (object) $notificationdata);
}
/**
* Returns a list of users the given user is in a conversation with.
*
* @param int $userid
* @return array
* @throws \dml_exception
*/
private static function get_userids_in_conversation_with(int $userid) {
global $DB;
$sql = "SELECT DISTINCT(useridfrom) as id
FROM {message} m
WHERE useridto = ?
AND notification = 0
UNION
SELECT DISTINCT(useridfrom) as id
FROM {message_read} m
WHERE useridto = ?
AND notification = 0";
$users = $DB->get_records_sql($sql, [$userid, $userid]);
$sql = "SELECT DISTINCT(useridto) as id
FROM {message} m
WHERE useridfrom = ?
AND notification = 0
UNION
SELECT DISTINCT(useridto) as id
FROM {message_read} m
WHERE useridfrom = ?
AND notification = 0";
return $users + $DB->get_records_sql($sql, [$userid, $userid]);
}
}

View file

@ -0,0 +1,553 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy provider tests.
*
* @package core_message
* @copyright 2018 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core_privacy\local\metadata\collection;
use core_message\privacy\provider;
use \core_privacy\local\request\writer;
use \core_privacy\local\request\transform;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider tests class.
*
* @package core_message
* @copyright 2018 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_message_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
/**
* Test for provider::get_metadata().
*/
public function test_get_metadata() {
$collection = new collection('core_message');
$newcollection = provider::get_metadata($collection);
$itemcollection = $newcollection->get_collection();
$this->assertCount(4, $itemcollection);
$messagetable = array_shift($itemcollection);
$this->assertEquals('message', $messagetable->get_name());
$messagereadtable = array_shift($itemcollection);
$this->assertEquals('message_read', $messagereadtable->get_name());
$messagecontacts = array_shift($itemcollection);
$this->assertEquals('message_contacts', $messagecontacts->get_name());
$usersettings = array_shift($itemcollection);
$this->assertEquals('core_message_messageprovider_settings', $usersettings->get_name());
$privacyfields = $messagetable->get_privacy_fields();
$this->assertArrayHasKey('useridfrom', $privacyfields);
$this->assertArrayHasKey('useridto', $privacyfields);
$this->assertArrayHasKey('subject', $privacyfields);
$this->assertArrayHasKey('fullmessage', $privacyfields);
$this->assertArrayHasKey('fullmessageformat', $privacyfields);
$this->assertArrayHasKey('fullmessagehtml', $privacyfields);
$this->assertArrayHasKey('smallmessage', $privacyfields);
$this->assertArrayHasKey('component', $privacyfields);
$this->assertArrayHasKey('eventtype', $privacyfields);
$this->assertArrayHasKey('contexturl', $privacyfields);
$this->assertArrayHasKey('contexturlname', $privacyfields);
$this->assertArrayHasKey('timecreated', $privacyfields);
$this->assertEquals('privacy:metadata:messages', $messagetable->get_summary());
$privacyfields = $messagereadtable->get_privacy_fields();
$this->assertArrayHasKey('useridfrom', $privacyfields);
$this->assertArrayHasKey('useridto', $privacyfields);
$this->assertArrayHasKey('subject', $privacyfields);
$this->assertArrayHasKey('fullmessage', $privacyfields);
$this->assertArrayHasKey('fullmessageformat', $privacyfields);
$this->assertArrayHasKey('fullmessagehtml', $privacyfields);
$this->assertArrayHasKey('smallmessage', $privacyfields);
$this->assertArrayHasKey('component', $privacyfields);
$this->assertArrayHasKey('eventtype', $privacyfields);
$this->assertArrayHasKey('contexturl', $privacyfields);
$this->assertArrayHasKey('contexturlname', $privacyfields);
$this->assertArrayHasKey('timeread', $privacyfields);
$this->assertArrayHasKey('timecreated', $privacyfields);
$this->assertEquals('privacy:metadata:messages', $messagereadtable->get_summary());
$privacyfields = $messagecontacts->get_privacy_fields();
$this->assertArrayHasKey('userid', $privacyfields);
$this->assertArrayHasKey('contactid', $privacyfields);
$this->assertArrayHasKey('blocked', $privacyfields);
$this->assertEquals('privacy:metadata:message_contacts', $messagecontacts->get_summary());
}
/**
* Test for provider::export_user_preferences().
*/
public function test_export_user_preferences_no_pref() {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
provider::export_user_preferences($user->id);
$writer = writer::with_context(\context_system::instance());
$this->assertFalse($writer->has_any_data());
}
/**
* Test for provider::export_user_preferences().
*/
public function test_export_user_preferences() {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
// Create another user to set a preference for who we won't be exporting.
$user = $this->getDataGenerator()->create_user();
// Set some message user preferences.
set_user_preference('message_provider_moodle_instantmessage_loggedin', 'airnotifier', $USER->id);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'popup', $USER->id);
set_user_preference('message_blocknoncontacts', 1, $USER->id);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'inbound', $user->id);
// Set an unrelated preference.
set_user_preference('block_myoverview_last_tab', 'courses', $USER->id);
provider::export_user_preferences($USER->id);
$writer = writer::with_context(\context_system::instance());
$this->assertTrue($writer->has_any_data());
$prefs = (array) $writer->get_user_preferences('core_message');
// Check only 3 preferences exist.
$this->assertCount(3, $prefs);
$this->assertArrayHasKey('message_provider_moodle_instantmessage_loggedin', $prefs);
$this->assertArrayHasKey('message_provider_moodle_instantmessage_loggedoff', $prefs);
$this->assertArrayHasKey('message_blocknoncontacts', $prefs);
foreach ($prefs as $key => $pref) {
if ($key == 'message_provider_moodle_instantmessage_loggedin') {
$this->assertEquals('airnotifier', $pref->value);
} else if ($key == 'message_provider_moodle_instantmessage_loggedoff') {
$this->assertEquals('popup', $pref->value);
} else {
$this->assertEquals(1, $pref->value);
}
}
}
/**
* Test for provider::get_contexts_for_userid().
*/
public function test_get_contexts_for_userid() {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$contextlist = provider::get_contexts_for_userid($user->id);
$this->assertCount(1, $contextlist);
$contextforuser = $contextlist->current();
$this->assertEquals(SYSCONTEXTID, $contextforuser->id);
}
/**
* Test for provider::export_user_data().
*/
public function test_export_for_context_with_contacts() {
$this->resetAfterTest();
// Create users to test with.
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$user4 = $this->getDataGenerator()->create_user();
// This user will not be added as a contact.
$this->getDataGenerator()->create_user();
message_add_contact($user2->id, 0, $user1->id);
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');
$writer = writer::with_context(\context_system::instance());
$contacts = (array) $writer->get_data([get_string('contacts', 'core_message')]);
$this->assertCount(3, $contacts);
$contact1 = array_shift($contacts);
$this->assertEquals($user2->id, $contact1->contact);
$this->assertEquals(get_string('no'), $contact1->blocked);
$contact2 = array_shift($contacts);
$this->assertEquals($user3->id, $contact2->contact);
$this->assertEquals(get_string('no'), $contact2->blocked);
$contact3 = array_shift($contacts);
$this->assertEquals($user4->id, $contact3->contact);
$this->assertEquals(get_string('yes'), $contact3->blocked);
}
/**
* Test for provider::export_user_data().
*/
public function test_export_for_context_with_messages() {
global $DB;
$this->resetAfterTest();
// Create users to test with.
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$now = time();
// Send messages from user 1 to user 2.
$m1 = $this->create_message_or_notification($user1->id, $user2->id, $now - (9 * DAYSECS), false, $now);
$m2 = $this->create_message_or_notification($user2->id, $user1->id, $now - (8 * DAYSECS));
$m3 = $this->create_message_or_notification($user1->id, $user2->id, $now - (7 * DAYSECS));
// Send messages from user 3 to user 1.
$m4 = $this->create_message_or_notification($user3->id, $user1->id, $now - (6 * DAYSECS), false, $now);
$m5 = $this->create_message_or_notification($user1->id, $user3->id, $now - (5 * DAYSECS));
$m6 = $this->create_message_or_notification($user3->id, $user1->id, $now - (4 * DAYSECS));
// Send messages from user 3 to user 2 - these should not be included in the export.
$m7 = $this->create_message_or_notification($user3->id, $user2->id, $now - (3 * DAYSECS), false, $now);
$m8 = $this->create_message_or_notification($user2->id, $user3->id, $now - (2 * DAYSECS));
$m9 = $this->create_message_or_notification($user3->id, $user2->id, $now - (1 * DAYSECS));
// Mark message 2 and 5 as deleted.
$dbm2 = $DB->get_record('message', ['id' => $m2]);
$dbm5 = $DB->get_record('message', ['id' => $m5]);
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');
$writer = writer::with_context(\context_system::instance());
$this->assertTrue($writer->has_any_data());
// Confirm the messages with user 2 are correct.
$messages = (array) $writer->get_data([get_string('messages', 'core_message'), fullname($user2)]);
$this->assertCount(3, $messages);
$dbm1 = $DB->get_record('message_read', ['id' => $m1]);
$dbm2 = $DB->get_record('message', ['id' => $m2]);
$dbm3 = $DB->get_record('message', ['id' => $m3]);
$m1 = array_shift($messages);
$m2 = array_shift($messages);
$m3 = array_shift($messages);
$this->assertEquals(get_string('yes'), $m1->sender);
$this->assertEquals(message_format_message_text($dbm1), $m1->message);
$this->assertEquals(transform::datetime($now - (9 * DAYSECS)), $m1->timecreated);
$this->assertNotEquals('-', $m1->timeread);
$this->assertArrayNotHasKey('timedeleted', (array) $m1);
$this->assertEquals(get_string('no'), $m2->sender);
$this->assertEquals(message_format_message_text($dbm2), $m2->message);
$this->assertEquals(transform::datetime($now - (8 * DAYSECS)), $m2->timecreated);
$this->assertEquals('-', $m2->timeread);
$this->assertArrayHasKey('timedeleted', (array) $m2);
$this->assertEquals(get_string('yes'), $m3->sender);
$this->assertEquals(message_format_message_text($dbm3), $m3->message);
$this->assertEquals(transform::datetime($now - (7 * DAYSECS)), $m3->timecreated);
$this->assertEquals('-', $m3->timeread);
// Confirm the messages with user 3 are correct.
$messages = (array) $writer->get_data([get_string('messages', 'core_message'), fullname($user3)]);
$this->assertCount(3, $messages);
$dbm4 = $DB->get_record('message_read', ['id' => $m4]);
$dbm5 = $DB->get_record('message', ['id' => $m5]);
$dbm6 = $DB->get_record('message', ['id' => $m6]);
$m4 = array_shift($messages);
$m5 = array_shift($messages);
$m6 = array_shift($messages);
$this->assertEquals(get_string('no'), $m4->sender);
$this->assertEquals(message_format_message_text($dbm4), $m4->message);
$this->assertEquals(transform::datetime($now - (6 * DAYSECS)), $m4->timecreated);
$this->assertNotEquals('-', $m4->timeread);
$this->assertArrayNotHasKey('timedeleted', (array) $m4);
$this->assertEquals(get_string('yes'), $m5->sender);
$this->assertEquals(message_format_message_text($dbm5), $m5->message);
$this->assertEquals(transform::datetime($now - (5 * DAYSECS)), $m5->timecreated);
$this->assertEquals('-', $m5->timeread);
$this->assertArrayHasKey('timedeleted', (array) $m5);
$this->assertEquals(get_string('no'), $m6->sender);
$this->assertEquals(message_format_message_text($dbm6), $m6->message);
$this->assertEquals(transform::datetime($now - (4 * DAYSECS)), $m6->timecreated);
$this->assertEquals('-', $m6->timeread);
}
/**
* Test for provider::export_user_data().
*/
public function test_export_for_context_with_notifications() {
$this->resetAfterTest();
// 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;
// Send notifications from user 1 to user 2.
$this->create_message_or_notification($user1->id, $user2->id, $now + (9 * DAYSECS), true, $timeread);
$this->create_message_or_notification($user2->id, $user1->id, $now + (8 * DAYSECS), true);
$this->create_message_or_notification($user1->id, $user2->id, $now + (7 * DAYSECS), true);
// Send notifications from user 3 to user 1.
$this->create_message_or_notification($user3->id, $user1->id, $now + (6 * DAYSECS), true, $timeread);
$this->create_message_or_notification($user1->id, $user3->id, $now + (5 * DAYSECS), true);
$this->create_message_or_notification($user3->id, $user1->id, $now + (4 * DAYSECS), true);
// Send notifications from user 3 to user 2 - should not be part of the export.
$this->create_message_or_notification($user3->id, $user2->id, $now + (3 * DAYSECS), true, $timeread);
$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');
$writer = writer::with_context(\context_system::instance());
$this->assertTrue($writer->has_any_data());
// Confirm the notifications.
$notifications = (array) $writer->get_data([get_string('notifications', 'core_message')]);
$this->assertCount(6, $notifications);
}
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context() {
global $DB;
$this->resetAfterTest();
// Create users to test with.
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$now = time();
$timeread = $now - DAYSECS;
$systemcontext = \context_system::instance();
// Create contacts.
message_add_contact($user1->id, 0, $user2->id);
message_add_contact($user2->id, 0, $user1->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));
// 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);
// 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 two unread messages.
$this->assertEquals(2, $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 two read notifications.
$this->assertEquals(2, $DB->count_records('message_read', ['notification' => 1]));
provider::delete_data_for_all_users_in_context($systemcontext);
// 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'));
}
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user() {
global $DB;
$this->resetAfterTest();
// 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;
// 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);
// 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));
// 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);
$n3 = $this->create_message_or_notification($user2->id, $user3->id, $now + (8 * DAYSECS), true);
$n4 = $this->create_message_or_notification($user3->id, $user2->id, $now + (8 * DAYSECS), true, $timeread);
// Delete one of the messages.
$dbm2 = $DB->get_record('message', ['id' => $m2]);
message_delete_message($dbm2, $user1->id);
// There should be three contacts.
$this->assertEquals(3, $DB->count_records('message_contacts'));
// There should be two unread messages.
$this->assertEquals(2, $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 two read notifications.
$this->assertEquals(2, $DB->count_records('message_read', ['notification' => 1]));
$systemcontext = \context_system::instance();
$contextlist = new \core_privacy\local\request\approved_contextlist($user1, 'core_message',
[$systemcontext->id]);
provider::delete_data_for_user($contextlist);
// Confirm the user 2 data still exists.
$contacts = $DB->get_records('message_contacts');
$messages = $DB->get_records('message', ['notification' => 0]);
$messagesread = $DB->get_records('message_read', ['notification' => 0]);
$notifications = $DB->get_records('message', ['notification' => 1]);
$notificationsread = $DB->get_records('message_read', ['notification' => 1]);
$this->assertCount(1, $contacts);
$contact = reset($contacts);
$this->assertEquals($user3->id, $contact->userid);
$this->assertEquals($user2->id, $contact->contactid);
$this->assertCount(1, $messages);
$message = reset($messages);
$this->assertEquals($m2, $message->id);
$this->assertCount(1, $messagesread);
$messagesread = reset($messagesread);
$this->assertEquals($m3, $messagesread->id);
$this->assertCount(1, $notifications);
$notifications = reset($notifications);
$this->assertEquals($n3, $notifications->id);
$this->assertCount(1, $notificationsread);
$notificationsread = reset($notificationsread);
$this->assertEquals($n4, $notificationsread->id);
}
/**
* Creates a message or notification to be used for testing.
*
* @param int $useridfrom The user id from
* @param int $useridto The user id to
* @param int $timecreated
* @param bool $notification
* @param int|null $timeread The time the message/notification was read, null if it hasn't been.
* @return int The id of the message (in either the message or message_read table)
* @throws dml_exception
*/
private function create_message_or_notification($useridfrom, $useridto, $timecreated = null,
$notification = false, $timeread = null) {
global $DB;
$tabledata = new \stdClass();
if (is_null($timecreated)) {
$timecreated = time();
}
if (!is_null($timeread)) {
$table = 'message_read';
$tabledata->timeread = $timeread;
} else {
$table = 'message';
}
if ($notification) {
$tabledata->eventtype = 'assign_notification';
$tabledata->component = 'mod_assign';
$tabledata->notification = 1;
$tabledata->contexturl = 'https://www.google.com';
$tabledata->contexturlname = 'google';
} else {
$tabledata->eventtype = 'instantmessage';
$tabledata->component = 'moodle';
$tabledata->notification = 0;
}
$tabledata->useridfrom = $useridfrom;
$tabledata->useridto = $useridto;
$tabledata->subject = 'Subject ' . $timecreated;
$tabledata->fullmessage = 'Full message ' . $timecreated;
$tabledata->fullmessageformat = FORMAT_PLAIN;
$tabledata->fullmessagehtml = 'Full message HTML ' . $timecreated;
$tabledata->smallmessage = 'Small message ' . $timecreated;
$tabledata->timecreated = $timecreated;
return $DB->insert_record($table, $tabledata);
}
}