MDL-63606 core_badges: Add support for removal of context users

This issue is part of the MDL-62560 Epic.
This commit is contained in:
Mihail Geshoski 2018-10-30 16:41:44 +08:00
parent 448bd578d8
commit 541982c01e
2 changed files with 266 additions and 0 deletions

View File

@ -24,6 +24,7 @@
*/
namespace core_badges\privacy;
defined('MOODLE_INTERNAL') || die();
use badge;
@ -37,6 +38,8 @@ use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use core_privacy\local\request\userlist;
use core_privacy\local\request\approved_userlist;
require_once($CFG->libdir . '/badgeslib.php');
@ -50,6 +53,7 @@ require_once($CFG->libdir . '/badgeslib.php');
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\subsystem\provider {
/**
@ -173,6 +177,78 @@ class provider implements
return $contextlist;
}
/**
* Get the list of users within a specific 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();
$allowedcontexts = [
CONTEXT_COURSE,
CONTEXT_SYSTEM,
CONTEXT_USER
];
if (!in_array($context->contextlevel, $allowedcontexts)) {
return;
}
if ($context->contextlevel == CONTEXT_COURSE || $context->contextlevel == CONTEXT_SYSTEM) {
// Find the modifications we made on badges (course & system).
$params = [
'courselevel' => CONTEXT_COURSE,
'syscontextid' => SYSCONTEXTID,
'typecourse' => BADGE_TYPE_COURSE,
'typesite' => BADGE_TYPE_SITE,
'contextid' => $context->id,
];
$sql = "SELECT b.usermodified, b.usercreated
FROM {badge} b
JOIN {context} ctx
ON (b.type = :typecourse AND b.courseid = ctx.instanceid AND ctx.contextlevel = :courselevel)
OR (b.type = :typesite AND ctx.id = :syscontextid)
WHERE ctx.id = :contextid";
$userlist->add_from_sql('usermodified', $sql, $params);
$userlist->add_from_sql('usercreated', $sql, $params);
}
if ($context->contextlevel == CONTEXT_USER) {
// Find where we've manually awarded a badge (recipient user context).
$params = [
'instanceid' => $context->instanceid
];
$sql = "SELECT issuerid, recipientid
FROM {badge_manual_award}
WHERE recipientid = :instanceid";
$userlist->add_from_sql('issuerid', $sql, $params);
$userlist->add_from_sql('recipientid', $sql, $params);
$sql = "SELECT userid
FROM {badge_issued}
WHERE userid = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
$sql = "SELECT userid
FROM {badge_criteria_met}
WHERE userid = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
$sql = "SELECT userid
FROM {badge_backpack}
WHERE userid = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
}
}
/**
* Export all user data for the specified user, in the specified contexts.
*
@ -439,6 +515,24 @@ class provider implements
static::delete_user_data($context->instanceid);
}
/**
* 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) {
$context = $userlist->get_context();
if (!in_array($context->instanceid, $userlist->get_userids())) {
return;
}
if ($context->contextlevel == CONTEXT_USER) {
// We can only delete our own data in the user context, nothing in course or system.
static::delete_user_data($context->instanceid);
}
}
/**
* Delete all user data for the specified user, in the specified contexts.
*

View File

@ -32,6 +32,7 @@ use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use core_badges\privacy\provider;
use core_privacy\local\request\approved_userlist;
require_once($CFG->libdir . '/badgeslib.php');
@ -399,6 +400,177 @@ class core_badges_privacy_testcase extends provider_testcase {
$this->assertEquals('Manager', $data->badges[0]['issuer_role']);
}
/**
* Test that only users within a user, system and course context are fetched.
*/
public function test_get_users_in_context() {
$component = 'core_badges';
// Create course1.
$course1 = $this->getDataGenerator()->create_course();
$coursecontext1 = context_course::instance($course1->id);
// Create course2.
$course2 = $this->getDataGenerator()->create_course();
$coursecontext2 = context_course::instance($course2->id);
// Create user1.
$user1 = $this->getDataGenerator()->create_user();
$usercontext1 = context_user::instance($user1->id);
// Create user2.
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = context_user::instance($user2->id);
// Create user3.
$user3 = $this->getDataGenerator()->create_user();
$usercontext3 = context_user::instance($user3->id);
// The list of users in usercontext1 should not return anything yet (related data still haven't been created).
$userlist1 = new \core_privacy\local\request\userlist($usercontext1, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(0, $userlist1);
// The list of users in coursecontext1 should not return anything yet (related data still haven't been created).
$userlist2 = new \core_privacy\local\request\userlist($coursecontext1, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(0, $userlist2);
// The list of users in systemcontext should not return anything yet (related data still haven't been created).
$systemcontext = context_system::instance();
$userlist3 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(0, $userlist3);
// Assert that we find contexts where we created/modified a badge.
$this->create_badge(['usercreated' => $user1->id, 'usermodified' => $user2->id]);
$badge1 = $this->create_badge(['usercreated' => $user2->id, 'type' => BADGE_TYPE_COURSE, 'courseid' => $course1->id]);
$badge2 = $this->create_badge(['usercreated' => $user3->id, 'usermodified' => $user1->id]);
$this->create_manual_award(['recipientid' => $user2->id, 'issuerid' => $user1->id, 'badgeid' => $badge1->id]);
$this->create_manual_award(['recipientid' => $user3->id, 'issuerid' => $user2->id, 'badgeid' => $badge1->id]);
$this->create_manual_award(['recipientid' => $user1->id, 'issuerid' => $user2->id, 'badgeid' => $badge2->id]);
$this->create_backpack(['userid' => $user2->id]);
$this->create_issued(['badgeid' => $badge2->id, 'userid' => $user3->id]);
$crit = $this->create_criteria_manual($badge1->id);
$crit->mark_complete($user3->id);
// The list of users for user context should return user1 and user2.
provider::get_users_in_context($userlist1);
$this->assertCount(2, $userlist1);
$this->assertTrue(in_array($user1->id, $userlist1->get_userids()));
$this->assertTrue(in_array($user2->id, $userlist1->get_userids()));
// The list of users for course context should return user2.
provider::get_users_in_context($userlist2);
$this->assertCount(1, $userlist2);
$this->assertTrue(in_array($user2->id, $userlist2->get_userids()));
// The list of users for system context should return user1, user2 and user3.
provider::get_users_in_context($userlist3);
$this->assertCount(3, $userlist3);
$this->assertTrue(in_array($user1->id, $userlist3->get_userids()));
$this->assertTrue(in_array($user2->id, $userlist3->get_userids()));
$this->assertTrue(in_array($user3->id, $userlist3->get_userids()));
}
/**
* Test that data for users in approved userlist is deleted.
*/
public function test_delete_data_for_users() {
$component = 'core_badges';
// Create course1.
$course1 = $this->getDataGenerator()->create_course();
$coursecontext1 = context_course::instance($course1->id);
// Create course2.
$course2 = $this->getDataGenerator()->create_course();
$coursecontext2 = context_course::instance($course2->id);
// Create user1.
$user1 = $this->getDataGenerator()->create_user();
$usercontext1 = context_user::instance($user1->id);
// Create user2.
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = context_user::instance($user2->id);
// Create user3.
$user3 = $this->getDataGenerator()->create_user();
$usercontext3 = context_user::instance($user3->id);
$this->create_badge(['usercreated' => $user1->id, 'usermodified' => $user2->id]);
$badge1 = $this->create_badge(['usercreated' => $user2->id, 'type' => BADGE_TYPE_COURSE, 'courseid' => $course1->id]);
$badge2 = $this->create_badge(['usercreated' => $user3->id, 'type' => BADGE_TYPE_COURSE, 'courseid' => $course2->id,
'usermodified' => $user1->id]);
$this->create_manual_award(['recipientid' => $user2->id, 'issuerid' => $user1->id, 'badgeid' => $badge1->id]);
$this->create_manual_award(['recipientid' => $user3->id, 'issuerid' => $user2->id, 'badgeid' => $badge1->id]);
$this->create_manual_award(['recipientid' => $user1->id, 'issuerid' => $user2->id, 'badgeid' => $badge2->id]);
$this->create_backpack(['userid' => $user2->id]);
$this->create_issued(['badgeid' => $badge2->id, 'userid' => $user3->id]);
$crit = $this->create_criteria_manual($badge1->id);
$crit->mark_complete($user3->id);
// The list of users for usercontext2 context should return users.
$userlist1 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(2, $userlist1);
$this->assertTrue(in_array($user1->id, $userlist1->get_userids()));
$this->assertTrue(in_array($user2->id, $userlist1->get_userids()));
// The list of users for coursecontext2 context should return users.
$userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(2, $userlist2);
$this->assertTrue(in_array($user1->id, $userlist2->get_userids()));
$this->assertTrue(in_array($user3->id, $userlist2->get_userids()));
// The list of users for system context should return users.
$systemcontext = context_system::instance();
$userlist3 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(2, $userlist3);
$this->assertTrue(in_array($user1->id, $userlist3->get_userids()));
$this->assertTrue(in_array($user2->id, $userlist3->get_userids()));
// Delete the data for user1 in usercontext2.
$approvedlist = new approved_userlist($usercontext2, $component, [$user1->id]);
// Delete using delete_data_for_user. No data for users in usercontext2 should be removed.
provider::delete_data_for_users($approvedlist);
// The list of users for usercontext2 context should still return user1, user2.
$userlist1 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(2, $userlist1);
$this->assertTrue(in_array($user1->id, $userlist1->get_userids()));
$this->assertTrue(in_array($user2->id, $userlist1->get_userids()));
// Delete the data for user2 in usercontext2.
$approvedlist = new approved_userlist($usercontext2, $component, [$user2->id]);
// Delete using delete_data_for_user. The user data in usercontext2 should be removed.
provider::delete_data_for_users($approvedlist);
// The list of users for usercontext2 context should not return any users.
$userlist1 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(0, $userlist1);
// The list of users for coursecontext2 context should return the previous users.
$userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(2, $userlist2);
// The list of users for system context should return the previous users.
$systemcontext = context_system::instance();
$userlist3 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(2, $userlist3);
// Make sure data is only deleted in the user context, nothing in course or system.
// Convert $userlist2 into an approved_contextlist.
$approvedlist = new approved_userlist($coursecontext2, $component, $userlist2->get_userids());
provider::delete_data_for_users($approvedlist);
// The list of users for coursecontext2 context should still return the user data.
$userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(2, $userlist2);
}
/**
* Create a badge.
*