Skip to content

Commit

Permalink
Merge branch 'MDL-63606-master-2' of git://github.com/mihailges/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewnicols committed Oct 31, 2018
2 parents 1710934 + 541982c commit 4b7418d
Show file tree
Hide file tree
Showing 2 changed files with 266 additions and 0 deletions.
94 changes: 94 additions & 0 deletions badges/classes/privacy/provider.php
Expand Up @@ -24,6 +24,7 @@
*/

namespace core_badges\privacy;

defined('MOODLE_INTERNAL') || die();

use badge;
Expand All @@ -37,6 +38,8 @@
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');

Expand All @@ -50,6 +53,7 @@
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\subsystem\provider {

/**
Expand Down Expand Up @@ -173,6 +177,78 @@ public static function get_contexts_for_userid(int $userid) : \core_privacy\loca
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.
*
Expand Down Expand Up @@ -439,6 +515,24 @@ public static function delete_data_for_all_users_in_context(context $context) {
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.
*
Expand Down
172 changes: 172 additions & 0 deletions badges/tests/privacy_test.php
Expand Up @@ -32,6 +32,7 @@
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');

Expand Down Expand Up @@ -399,6 +400,177 @@ public function test_export_data_for_user() {
$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.
*
Expand Down

0 comments on commit 4b7418d

Please sign in to comment.