Skip to content

Commit

Permalink
MDL-63500 core_group: support removal of multiple users in a context
Browse files Browse the repository at this point in the history
This issue is part of the MDL-62560 Epic.
  • Loading branch information
rezaies authored and David Monllao committed Oct 22, 2018
1 parent bb65ee1 commit e114ac6
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 1 deletion.
99 changes: 98 additions & 1 deletion group/classes/privacy/provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@

use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\userlist;

/**
* Privacy Subsystem implementation for core_group.
Expand All @@ -46,7 +48,10 @@ class provider implements
\core_privacy\local\request\subsystem\provider,

// The group subsystem can provide information to other plugins.
\core_privacy\local\request\subsystem\plugin_provider {
\core_privacy\local\request\subsystem\plugin_provider,

// This plugin is capable of determining which users have data within it.
\core_privacy\local\request\core_userlist_provider {

/**
* Returns meta data about this system.
Expand Down Expand Up @@ -190,6 +195,73 @@ public static function delete_groups_for_user(approved_contextlist $contextlist,
\cache_helper::invalidate_by_definition('core', 'user_group_groupings', array(), array($userid));
}

/**
* Add the list of users who are members of some groups in the specified constraints.
*
* @param userlist $userlist The userlist to add the users to.
* @param string $component The component to check.
* @param int $itemid Optional itemid associated with component.
*/
public static function get_group_members_in_context(userlist $userlist, string $component, int $itemid = 0) {
$context = $userlist->get_context();

if (!$context instanceof \context_course) {
return;
}

// Group members in the given context.
$sql = "SELECT gm.userid
FROM {groups_members} gm
JOIN {groups} g ON gm.groupid = g.id
WHERE g.courseid = :courseid AND gm.component = :component";
$params = [
'courseid' => $context->instanceid,
'component' => $component
];

if ($itemid) {
$sql .= ' AND gm.itemid = :itemid';
$params['itemid'] = $itemid;
}

$userlist->add_from_sql('userid', $sql, $params);
}

/**
* Deletes all records for multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
* @param string $component Component to delete from. Empty string means no component (manual memberships).
* @param int $itemid Optional itemid associated with component.
*/
public static function delete_groups_for_users(approved_userlist $userlist, string $component, int $itemid = 0) {
global $DB;

$context = $userlist->get_context();
$userids = $userlist->get_userids();

list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);

$groupselect = "SELECT g.id
FROM {groups} g
JOIN {context} ctx ON g.courseid = ctx.instanceid AND ctx.contextlevel = :contextcourse
WHERE ctx.id = :contextid";
$groupparams = ['contextid' => $context->id, 'contextcourse' => CONTEXT_COURSE];

$select = "component = :component AND userid {$usersql} AND groupid IN ({$groupselect})";
$params = ['component' => $component] + $groupparams + $userparams;

if ($itemid) {
$select .= ' AND itemid = :itemid';
$params['itemid'] = $itemid;
}

$DB->delete_records_select('groups_members', $select, $params);

// Invalidate the group and grouping cache for the user.
\cache_helper::invalidate_by_definition('core', 'user_group_groupings', array(), $userids);
}

/**
* Get the list of contexts that contain user information for the specified user.
*
Expand All @@ -215,6 +287,21 @@ public static function get_contexts_for_userid(int $userid) : contextlist {
return $contextlist;
}

/**
* Get the list of users who have data within a 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();

if (!$context instanceof \context_course) {
return;
}

static::get_group_members_in_context($userlist, '');
}

/**
* Export all user data for the specified user, in the specified contexts.
*
Expand Down Expand Up @@ -245,4 +332,14 @@ public static function delete_data_for_all_users_in_context(\context $context) {
public static function delete_data_for_user(approved_contextlist $contextlist) {
static::delete_groups_for_user($contextlist, '');
}

/**
* 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) {
static::delete_groups_for_users($userlist, '');
}

}
116 changes: 116 additions & 0 deletions group/tests/privacy_provider_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -789,4 +789,120 @@ public function test_delete_data_for_user() {
WHERE gm.userid = ?", [$user1->id])
);
}

/**
* Test for provider::delete_data_for_users().
*/
public function test_delete_data_for_users() {
global $DB;

$this->resetAfterTest();

$course1 = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();

$group1a = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
$group1b = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
$group1c = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
$group2a = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));
$group2b = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));
$group2c = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));

$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();

$this->getDataGenerator()->enrol_user($user1->id, $course1->id);
$this->getDataGenerator()->enrol_user($user1->id, $course2->id);
$this->getDataGenerator()->enrol_user($user2->id, $course1->id);
$this->getDataGenerator()->enrol_user($user2->id, $course2->id);
$this->getDataGenerator()->enrol_user($user3->id, $course1->id);
$this->getDataGenerator()->enrol_user($user3->id, $course2->id);

$this->getDataGenerator()->create_group_member(array('groupid' => $group1a->id, 'userid' => $user1->id));
$this->getDataGenerator()->create_group_member(array('groupid' => $group1b->id, 'userid' => $user2->id));
$this->getDataGenerator()->create_group_member(array('groupid' => $group1c->id, 'userid' => $user3->id));
$this->getDataGenerator()->create_group_member(array('groupid' => $group2a->id, 'userid' => $user1->id));
$this->getDataGenerator()->create_group_member(array('groupid' => $group2b->id, 'userid' => $user2->id));
$this->getDataGenerator()->create_group_member(array('groupid' => $group2c->id, 'userid' => $user3->id));

$this->assertEquals(
3,
$DB->count_records_sql("SELECT COUNT(gm.id)
FROM {groups_members} gm
JOIN {groups} g ON gm.groupid = g.id
WHERE g.courseid = ?", [$course1->id])
);
$this->assertEquals(
3,
$DB->count_records_sql("SELECT COUNT(gm.id)
FROM {groups_members} gm
JOIN {groups} g ON gm.groupid = g.id
WHERE g.courseid = ?", [$course2->id])
);

$coursecontext1 = context_course::instance($course1->id);
$approveduserlist = new \core_privacy\local\request\approved_userlist($coursecontext1, 'core_group',
[$user1->id, $user2->id]);
provider::delete_data_for_users($approveduserlist);

$this->assertEquals(
[$user3->id],
$DB->get_fieldset_sql("SELECT gm.userid
FROM {groups_members} gm
JOIN {groups} g ON gm.groupid = g.id
WHERE g.courseid = ?", [$course1->id])
);
$this->assertEquals(
3,
$DB->count_records_sql("SELECT COUNT(gm.id)
FROM {groups_members} gm
JOIN {groups} g ON gm.groupid = g.id
WHERE g.courseid = ?", [$course2->id])
);
}

/**
* Test for provider::get_users_in_context().
*/
public function test_get_users_in_context() {
$this->resetAfterTest();

$course1 = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();

$group1a = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
$group1b = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
$group2a = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));
$group2b = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));

$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();

$this->getDataGenerator()->enrol_user($user1->id, $course1->id);
$this->getDataGenerator()->enrol_user($user1->id, $course2->id);
$this->getDataGenerator()->enrol_user($user2->id, $course1->id);
$this->getDataGenerator()->enrol_user($user2->id, $course2->id);
$this->getDataGenerator()->enrol_user($user3->id, $course1->id);
$this->getDataGenerator()->enrol_user($user3->id, $course2->id);

$this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1a->id));
$this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group2a->id));
$this->getDataGenerator()->create_group_member(array('userid' => $user2->id, 'groupid' => $group1b->id));
$this->getDataGenerator()->create_group_member(array('userid' => $user2->id, 'groupid' => $group2b->id));
$this->getDataGenerator()->create_group_member(array('userid' => $user3->id, 'groupid' => $group2a->id));

$coursecontext1 = context_course::instance($course1->id);

$userlist = new \core_privacy\local\request\userlist($coursecontext1, 'core_group');
\core_group\privacy\provider::get_users_in_context($userlist);

// Only user1 and user2. User3 is not member of any group in course1.
$this->assertCount(2, $userlist);
$this->assertEquals(
[$user1->id, $user2->id],
$userlist->get_userids(),
'', 0.0, 10, true);
}
}

0 comments on commit e114ac6

Please sign in to comment.