MDL-63969 core_favourites: Add support for removal of context users

This commit is contained in:
Mihail Geshoski 2018-11-16 12:18:22 +08:00
parent dccda6546b
commit 61fafe8127
2 changed files with 291 additions and 18 deletions

View File

@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
use \core_privacy\local\metadata\collection;
use \core_privacy\local\request\context;
use \core_privacy\local\request\approved_contextlist;
use \core_privacy\local\request\transform;
/**
* Privacy class for requesting user data.
@ -36,7 +37,10 @@ use \core_privacy\local\request\approved_contextlist;
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.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\plugin_provider {
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\subsystem\plugin_provider,
\core_privacy\local\request\shared_userlist_provider {
/**
* Returns metadata about this system.
@ -86,13 +90,82 @@ class provider implements \core_privacy\local\metadata\provider, \core_privacy\l
FROM {favourite} f
WHERE userid = :userid
AND component = :component";
$params = ['userid' => $userid, 'component' => $component];
if (!is_null($itemtype)) {
$sql .= " AND itemtype = :itemtype";
$params['itemtype'] = $itemtype;
}
$params = ['userid' => $userid, 'component' => $component, 'itemtype' => $itemtype];
$contextlist->add_from_sql($sql, $params);
}
/**
* Add users to a userlist who have favourites within the specified context.
*
* @param \core_privacy\local\request\userlist $userlist The userlist to add the users to.
* @param string $itemtype the type of the favourited items.
* @return void
*/
public static function add_userids_for_context(\core_privacy\local\request\userlist $userlist,
string $itemtype = null) {
if (empty($userlist)) {
return;
}
$params = [
'contextid' => $userlist->get_context()->id,
'component' => $userlist->get_component()
];
$sql = "SELECT userid
FROM {favourite}
WHERE contextid = :contextid
AND component = :component";
if (!is_null($itemtype)) {
$sql .= " AND itemtype = :itemtype";
$params['itemtype'] = $itemtype;
}
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Get favourites data for the specified user in the specified component, item type and item ID.
*
* @param int $userid The id of the user in scope.
* @param \context $context The context to which data is scoped.
* @param string $component The favourite's component name.
* @param string $itemtype The favourite's item type.
* @param int $itemid The favourite's item ID.
* @return array|null
*/
public static function get_favourites_info_for_user(int $userid, \context $context,
string $component, string $itemtype, int $itemid) {
global $DB;
$params = [
'userid' => $userid,
'component' => $component,
'itemtype' => $itemtype,
'itemid' => $itemid,
'contextid' => $context->id
];
if (!$favourited = $DB->get_record('favourite', $params)) {
return;
}
return [
'starred' => transform::yesno(true),
'ordering' => $favourited->ordering,
'timecreated' => transform::datetime($favourited->timecreated),
'timemodified' => transform::datetime($favourited->timemodified)
];
}
/**
* Delete all favourites for all users in the specified contexts, and component area.
*
@ -114,6 +187,39 @@ class provider implements \core_privacy\local\metadata\provider, \core_privacy\l
$DB->delete_records_select('favourite', $select, $params);
}
/**
* Delete all favourites for the specified users in the specified context, component area and item type.
*
* @param \core_privacy\local\request\approved_userlist $userlist The approved contexts and user information
* to delete information for.
* @param string $itemtype The favourite's itemtype.
* @throws \dml_exception if any errors are encountered during deletion.
*/
public static function delete_favourites_for_userlist(\core_privacy\local\request\approved_userlist $userlist,
string $itemtype) {
global $DB;
$userids = $userlist->get_userids();
if (empty($userids)) {
return;
}
$context = $userlist->get_context();
list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$params = [
'component' => $userlist->get_component(),
'itemtype' => $itemtype,
'contextid' => $context->id
];
$params += $userparams;
$select = "component = :component AND itemtype = :itemtype AND contextid = :contextid AND userid $usersql";
$DB->delete_records_select('favourite', $select, $params);
}
/**
* Delete all favourites for the specified user, in the specified contexts.
*

View File

@ -27,6 +27,7 @@ defined('MOODLE_INTERNAL') || die();
use \core_privacy\tests\provider_testcase;
use \core_favourites\privacy\provider;
use \core_privacy\local\request\transform;
/**
* Unit tests for favourites/classes/privacy/provider
@ -65,25 +66,25 @@ class privacy_test extends provider_testcase {
$ufservice1 = \core_favourites\service_factory::get_service_for_user_context($user1context);
$ufservice2 = \core_favourites\service_factory::get_service_for_user_context($user2context);
$systemcontext = context_system::instance();
$ufservice1->create_favourite('core_course', 'course', $course1context->instanceid, $systemcontext);
$ufservice1->create_favourite('core_course', 'course', $course2context->instanceid, $systemcontext);
$ufservice2->create_favourite('core_course', 'course', $course2context->instanceid, $systemcontext);
$this->assertCount(2, $ufservice1->find_favourites_by_type('core_course', 'course'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'course'));
$ufservice1->create_favourite('core_course', 'courses', $course1context->instanceid, $systemcontext);
$ufservice1->create_favourite('core_course', 'courses', $course2context->instanceid, $systemcontext);
$ufservice2->create_favourite('core_course', 'courses', $course2context->instanceid, $systemcontext);
$this->assertCount(2, $ufservice1->find_favourites_by_type('core_course', 'courses'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'courses'));
// Now, just for variety, let's assume you can favourite a course at user context, and do so for user1.
$ufservice1->create_favourite('core_course', 'course', $course1context->instanceid, $user1context);
$ufservice1->create_favourite('core_course', 'courses', $course1context->instanceid, $user1context);
// Now, ask the favourites privacy api to export contexts for favourites of the type we just created, for user1.
$contextlist = new \core_privacy\local\request\contextlist();
\core_favourites\privacy\provider::add_contexts_for_userid($contextlist, $user1->id, 'core_course', 'course');
\core_favourites\privacy\provider::add_contexts_for_userid($contextlist, $user1->id, 'core_course', 'courses');
// Verify we have two contexts in the list for user1.
$this->assertCount(2, $contextlist->get_contextids());
// And verify we only have the system context returned for user2.
$contextlist = new \core_privacy\local\request\contextlist();
\core_favourites\privacy\provider::add_contexts_for_userid($contextlist, $user2->id, 'core_course', 'course');
\core_favourites\privacy\provider::add_contexts_for_userid($contextlist, $user2->id, 'core_course', 'courses');
$this->assertCount(1, $contextlist->get_contextids());
}
@ -96,19 +97,19 @@ class privacy_test extends provider_testcase {
// Favourite 2 courses for user1 and 1 course for user2, all at the user context.
$ufservice1 = \core_favourites\service_factory::get_service_for_user_context($user1context);
$ufservice2 = \core_favourites\service_factory::get_service_for_user_context($user2context);
$ufservice1->create_favourite('core_course', 'course', $course1context->instanceid, $user1context);
$ufservice1->create_favourite('core_course', 'course', $course2context->instanceid, $user1context);
$ufservice2->create_favourite('core_course', 'course', $course2context->instanceid, $user2context);
$this->assertCount(2, $ufservice1->find_favourites_by_type('core_course', 'course'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'course'));
$ufservice1->create_favourite('core_course', 'courses', $course1context->instanceid, $user1context);
$ufservice1->create_favourite('core_course', 'courses', $course2context->instanceid, $user1context);
$ufservice2->create_favourite('core_course', 'courses', $course2context->instanceid, $user2context);
$this->assertCount(2, $ufservice1->find_favourites_by_type('core_course', 'courses'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'courses'));
// Now, delete the favourites for user1 only.
$approvedcontextlist = new \core_privacy\local\request\approved_contextlist($user1, 'core_course', [$user1context->id]);
provider::delete_favourites_for_user($approvedcontextlist, 'core_course', 'course');
provider::delete_favourites_for_user($approvedcontextlist, 'core_course', 'courses');
// Verify that we have no favourite courses for user1 but that the records are in tact for user2.
$this->assertCount(0, $ufservice1->find_favourites_by_type('core_course', 'course'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'course'));
$this->assertCount(0, $ufservice1->find_favourites_by_type('core_course', 'courses'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'courses'));
}
public function test_delete_favourites_for_all_users() {
@ -134,4 +135,170 @@ class privacy_test extends provider_testcase {
$this->assertCount(0, $ufservice1->find_favourites_by_type('core_course', 'modules'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'modules'));
}
/**
* Test confirming that user ID's of favourited items can be added to the userlist.
*/
public function test_add_userids_for_context() {
list($user1, $user2, $user1context, $user2context, $course1context, $course2context) = $this->set_up_courses_and_users();
// Favourite 2 courses for user1 and 1 course for user2, all at the site context.
$ufservice1 = \core_favourites\service_factory::get_service_for_user_context($user1context);
$ufservice2 = \core_favourites\service_factory::get_service_for_user_context($user2context);
$systemcontext = context_system::instance();
$ufservice1->create_favourite('core_course', 'courses', $course1context->instanceid, $systemcontext);
$ufservice1->create_favourite('core_course', 'courses', $course2context->instanceid, $systemcontext);
$ufservice2->create_favourite('core_course', 'courses', $course2context->instanceid, $systemcontext);
$this->assertCount(2, $ufservice1->find_favourites_by_type('core_course', 'courses'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'courses'));
// Now, just for variety, let's assume you can favourite a course at user context, and do so for user1.
$ufservice1->create_favourite('core_course', 'courses', $course1context->instanceid, $user1context);
// Now, ask the favourites privacy api to export userids for favourites of the type we just created, in the system context.
$userlist = new \core_privacy\local\request\userlist($systemcontext, 'core_course');
provider::add_userids_for_context($userlist, 'courses');
// Verify we have two userids in the list for system context.
$this->assertCount(2, $userlist->get_userids());
$expected = [
$user1->id,
$user2->id
];
$this->assertEquals($expected, $userlist->get_userids(), '', 0.0, 10, true);
// Ask the favourites privacy api to export userids for favourites of the type we just created, in the user1 context.
$userlist = new \core_privacy\local\request\userlist($user1context, 'core_course');
provider::add_userids_for_context($userlist, 'courses');
// Verify we have one userid in the list for user1 context.
$this->assertCount(1, $userlist->get_userids());
$expected = [$user1->id];
$this->assertEquals($expected, $userlist->get_userids());
// Ask the favourites privacy api to export userids for favourites of the type we just created, in the user2 context.
$userlist = new \core_privacy\local\request\userlist($user2context, 'core_favourites');
provider::add_userids_for_context($userlist, 'core_course', 'courses');
// Verify we do not have any userids in the list for user2 context.
$this->assertCount(0, $userlist->get_userids());
}
/**
* Test deletion of user favourites based on an approved_userlist, component area and item type.
*/
public function test_delete_favourites_for_userlist() {
list($user1, $user2, $user1context, $user2context, $course1context, $course2context) = $this->set_up_courses_and_users();
// Favourite 2 courses for user1 and 1 course for user2.
$systemcontext = context_system::instance();
$ufservice1 = \core_favourites\service_factory::get_service_for_user_context($user1context);
$ufservice2 = \core_favourites\service_factory::get_service_for_user_context($user2context);
$ufservice1->create_favourite('core_course', 'courses', $course1context->instanceid, $systemcontext);
$ufservice1->create_favourite('core_course', 'courses', $course2context->instanceid, $user1context);
$ufservice2->create_favourite('core_course', 'courses', $course2context->instanceid, $systemcontext);
$this->assertCount(2, $ufservice1->find_favourites_by_type('core_course', 'courses'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'courses'));
// Ask the favourites privacy api to export userids for favourites of the type we just created, in the system context.
$userlist1 = new \core_privacy\local\request\userlist($systemcontext, 'core_course');
provider::add_userids_for_context($userlist1, 'courses');
// Verify we have two userids in the list for system context.
$this->assertCount(2, $userlist1->get_userids());
// Ask the favourites privacy api to export userids for favourites of the type we just created, in the user1 context.
$userlist2 = new \core_privacy\local\request\userlist($user1context, 'core_course');
provider::add_userids_for_context($userlist2, 'courses');
// Verify we have one userid in the list for user1 context.
$this->assertCount(1, $userlist2->get_userids());
// Now, delete the favourites for user1 only in the system context.
$approveduserlist = new \core_privacy\local\request\approved_userlist($systemcontext, 'core_course',
[$user1->id]);
provider::delete_favourites_for_userlist($approveduserlist, 'courses');
// Ensure user1's data was deleted and user2 is still returned for system context.
$userlist1 = new \core_privacy\local\request\userlist($systemcontext, 'core_course');
provider::add_userids_for_context($userlist1, 'courses');
$this->assertCount(1, $userlist1->get_userids());
// Verify that user2 is still in the list for system context.
$expected = [$user2->id];
$this->assertEquals($expected, $userlist1->get_userids());
// Verify that the data of user1 was not deleted in the user1context.
$userlist2 = new \core_privacy\local\request\userlist($user1context, 'core_course');
provider::add_userids_for_context($userlist2, 'courses');
$expected = [$user1->id];
$this->assertEquals($expected, $userlist2->get_userids());
// Now, delete the favourites for user2 only in the user1 context.
// Make sure favourites are only being deleted in the right context.
$approveduserlist = new \core_privacy\local\request\approved_userlist($user1context, 'core_course',
[$user2->id]);
provider::delete_favourites_for_userlist($approveduserlist, 'courses');
// Verify we have one userid in the list for system context.
$userlist2 = new \core_privacy\local\request\userlist($systemcontext, 'core_course');
provider::add_userids_for_context($userlist2, 'courses');
$this->assertCount(1, $userlist2->get_userids());
// Verify that user2 is still in the list for system context.
$expected = [$user2->id];
$this->assertEquals($expected, $userlist2->get_userids());
// Verify that user1 is still present in the list for user1 context.
$userlist3 = new \core_privacy\local\request\userlist($user1context, 'core_course');
provider::add_userids_for_context($userlist3, 'courses');
$this->assertCount(1, $userlist3->get_userids());
// Verify that user1 is still in the list for user1 context.
$expected = [$user1->id];
$this->assertEquals($expected, $userlist3->get_userids());
}
/**
* Test fetching the favourites data for a specified user in a specified component, item type and item ID.
*/
public function test_get_favourites_info_for_user() {
list($user1, $user2, $user1context, $user2context, $course1context, $course2context) = $this->set_up_courses_and_users();
// Favourite 2 courses for user1 and 1 course for user2.
$ufservice1 = \core_favourites\service_factory::get_service_for_user_context($user1context);
$ufservice2 = \core_favourites\service_factory::get_service_for_user_context($user2context);
$coursefavourite1 = $ufservice1->create_favourite('core_course', 'courses',
$course1context->instanceid, $course1context);
$this->waitForSecond();
$coursefavourite2 = $ufservice1->create_favourite('core_course', 'courses',
$course2context->instanceid, $course2context);
$this->waitForSecond();
$coursefavourite3 = $ufservice2->create_favourite('core_course', 'courses',
$course2context->instanceid, $course2context);
$this->assertCount(2, $ufservice1->find_favourites_by_type('core_course', 'courses'));
$this->assertCount(1, $ufservice2->find_favourites_by_type('core_course', 'courses'));
// Get the favourites info for user1 in the course1 context.
$favouriteinfo1 = (object) provider::get_favourites_info_for_user($user1->id, $course1context,
'core_course', 'courses', $course1context->instanceid);
// Ensure the correct data has been returned.
$this->assertEquals(transform::yesno(true), $favouriteinfo1->starred);
$this->assertEquals('', $favouriteinfo1->ordering);
$this->assertEquals(transform::datetime($coursefavourite1->timecreated), $favouriteinfo1->timecreated);
$this->assertEquals(transform::datetime($coursefavourite1->timemodified), $favouriteinfo1->timemodified);
// Get the favourites info for user1 in the course2 context.
$favouriteinfo2 = (object) provider::get_favourites_info_for_user($user1->id, $course2context,
'core_course', 'courses', $course2context->instanceid);
// Ensure the correct data has been returned.
$this->assertEquals(transform::yesno(true), $favouriteinfo2->starred);
$this->assertEquals('', $favouriteinfo2->ordering);
$this->assertEquals(transform::datetime($coursefavourite2->timecreated), $favouriteinfo2->timecreated);
$this->assertEquals(transform::datetime($coursefavourite2->timemodified), $favouriteinfo2->timemodified);
// Get the favourites info for user2 in the course2 context.
$favouriteinfo3 = (object) provider::get_favourites_info_for_user($user2->id, $course2context,
'core_course', 'courses', $course2context->instanceid);
// Ensure the correct data has been returned.
$this->assertEquals(transform::yesno(true), $favouriteinfo3->starred);
$this->assertEquals('', $favouriteinfo3->ordering);
$this->assertEquals(transform::datetime($coursefavourite3->timecreated), $favouriteinfo3->timecreated);
$this->assertEquals(transform::datetime($coursefavourite3->timemodified), $favouriteinfo3->timemodified);
// Get the favourites info for user2 in the course1 context (user2 has not favourited course1).
$favouriteinfo4 = provider::get_favourites_info_for_user($user2->id, $course1context,
'core_course', 'courses', $course1context->instanceid);
// Ensure that data has not been returned.
$this->assertEmpty($favouriteinfo4);
}
}