Skip to content

Commit

Permalink
MDL-63671 tool_cohortroles: Limit data to the system context in provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Mihail Geshoski committed Nov 8, 2018
1 parent 08c51ff commit a128601
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 111 deletions.
167 changes: 121 additions & 46 deletions admin/tool/cohortroles/classes/privacy/provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,25 @@ public static function get_metadata(collection $collection) : collection {
public static function get_contexts_for_userid(int $userid) : contextlist {
$contextlist = new contextlist();

// Retrieve the User context associated with tool_cohortroles records.
$sql = "SELECT DISTINCT c.id
FROM {context} c
JOIN {tool_cohortroles} cr ON cr.userid = c.instanceid AND c.contextlevel = :contextuser
WHERE cr.userid = :userid";
// When we process user deletions and expiries, we always delete from the user context.
// As a result the cohort role assignments would be deleted, which has a knock-on effect with courses
// as roles may change and data may be removed earlier than it should be.

// Retrieve the context associated with tool_cohortroles records.
$sql = "SELECT DISTINCT c.contextid
FROM {tool_cohortroles} tc
JOIN {cohort} c
ON tc.cohortid = c.id
JOIN {context} ctx
ON ctx.id = c.contextid
WHERE tc.userid = :userid
AND (ctx.contextlevel = :contextlevel1
OR ctx.contextlevel = :contextlevel2)";

$params = [
'contextuser' => CONTEXT_USER,
'userid' => $userid
'userid' => $userid,
'contextlevel1' => CONTEXT_SYSTEM,
'contextlevel2' => CONTEXT_COURSECAT
];

$contextlist->add_from_sql($sql, $params);
Expand All @@ -104,24 +114,29 @@ public static function get_contexts_for_userid(int $userid) : contextlist {
public static function get_users_in_context(userlist $userlist) {
$context = $userlist->get_context();

// We should process user data from the system context.
// When we process user deletions and expiries, we always delete from the user context.
// As a result the cohort role assignments would be deleted, which has a knock-on effect with courses
// as roles may change and data may be removed earlier than it should be.
if (!$context instanceof \context_system) {
return;
}

$params = [
'contextid' => $context->id
$allowedcontextlevels = [
CONTEXT_SYSTEM,
CONTEXT_COURSECAT
];

if (!in_array($context->contextlevel, $allowedcontextlevels)) {
return;
}

$sql = "SELECT tc.userid as userid
FROM {tool_cohortroles} tc
JOIN {cohort} c
ON tc.cohortid = c.id
WHERE c.contextid = :contextid";

$params = [
'contextid' => $context->id
];

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

Expand All @@ -133,38 +148,42 @@ public static function get_users_in_context(userlist $userlist) {
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;

// If the user has tool_cohortroles data, then only the User context should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
return;
}
$context = reset($contexts);
// Remove contexts different from SYSTEM or COURSECAT.
$contextids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
if ($context->contextlevel == CONTEXT_SYSTEM || $context->contextlevel == CONTEXT_COURSECAT) {
$carry[] = $context->id;
}
return $carry;
}, []);

// Sanity check that context is at the User context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
if (empty($contextids)) {
return;
}
$userid = $context->instanceid;

$userid = $contextlist->get_user()->id;

list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);

// Retrieve the tool_cohortroles records created for the user.
$sql = 'SELECT cr.id as cohortroleid,
$sql = "SELECT cr.id as cohortroleid,
c.name as cohortname,
c.idnumber as cohortidnumber,
c.description as cohortdescription,
c.contextid as contextid,
r.shortname as roleshortname,
cr.userid as userid,
cr.timecreated as timecreated,
cr.timemodified as timemodified
FROM {tool_cohortroles} cr
JOIN {cohort} c ON c.id = cr.cohortid
JOIN {role} r ON r.id = cr.roleid
WHERE cr.userid = :userid';
WHERE cr.userid = :userid
AND c.contextid {$contextsql}";

$params = [
'userid' => $userid
];
$params = ['userid' => $userid] + $contextparams;

$cohortroles = $DB->get_records_sql($sql, $params);

foreach ($cohortroles as $cohortrole) {
// The tool_cohortroles data export is organised in:
// {User Context}/Cohort roles management/{cohort name}/{role shortname}/data.json.
Expand All @@ -184,6 +203,8 @@ public static function export_user_data(approved_contextlist $contextlist) {
'timemodified' => transform::datetime($cohortrole->timemodified)
];

$context = \context::instance_by_id($cohortrole->contextid);

writer::with_context($context)->export_data($subcontext, $data);
}
}
Expand All @@ -196,14 +217,24 @@ public static function export_user_data(approved_contextlist $contextlist) {
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;

// Sanity check that context is at the User context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
// When we process user deletions and expiries, we always delete from the user context.
// As a result the cohort role assignments would be deleted, which has a knock-on effect with courses
// as roles may change and data may be removed earlier than it should be.

$allowedcontextlevels = [
CONTEXT_SYSTEM,
CONTEXT_COURSECAT
];

if (!in_array($context->contextlevel, $allowedcontextlevels)) {
return;
}
$userid = $context->instanceid;

// Delete the tool_cohortroles records created for the userid.
$DB->delete_records('tool_cohortroles', ['userid' => $userid]);
$cohortids = $DB->get_fieldset_select('cohort', 'id', 'contextid = :contextid',
['contextid' => $context->id]);

// Delete the tool_cohortroles records created in the specific context.
$DB->delete_records_list('tool_cohortroles', 'cohortid', $cohortids);
}

/**
Expand All @@ -214,15 +245,42 @@ public static function delete_data_for_all_users_in_context(\context $context) {
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;

$context = $userlist->get_context();

// We should process user data from the system context.
// When we process user deletions and expiries, we always delete from the user context.
// As a result the cohort role assignments would be deleted, which has a knock-on effect with courses
// as roles may change and data may be removed earlier than it should be.
if ($context instanceof \context_system) {
$DB->delete_records_list('tool_cohortroles', 'userid', $userlist->get_userids());

$userids = $userlist->get_userids();

if (empty($userids)) {
return;
}

$context = $userlist->get_context();

$allowedcontextlevels = [
CONTEXT_SYSTEM,
CONTEXT_COURSECAT
];

if (!in_array($context->contextlevel, $allowedcontextlevels)) {
return;
}

$cohortids = $DB->get_fieldset_select('cohort', 'id', 'contextid = :contextid',
['contextid' => $context->id]);

if (empty($cohortids)) {
return;
}

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

$params = $cohortparams + $userparams;
$select = "cohortid {$cohortsql} AND userid {$usersql}";

// Delete the tool_cohortroles records created in the specific context for an approved list of users.
$DB->delete_records_select('tool_cohortroles', $select, $params);
}

/**
Expand All @@ -233,21 +291,38 @@ public static function delete_data_for_users(approved_userlist $userlist) {
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;

// If the user has tool_cohortroles data, then only the User context should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
// When we process user deletions and expiries, we always delete from the user context.
// As a result the cohort role assignments would be deleted, which has a knock-on effect with courses
// as roles may change and data may be removed earlier than it should be.

// Remove contexts different from SYSTEM or COURSECAT.
$contextids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
if ($context->contextlevel == CONTEXT_SYSTEM || $context->contextlevel == CONTEXT_COURSECAT) {
$carry[] = $context->id;
}
return $carry;
}, []);

if (empty($contextids)) {
return;
}
$context = reset($contexts);

// Sanity check that context is at the User context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
$userid = $contextlist->get_user()->id;

list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
$selectcontext = "contextid {$contextsql}";
// Get the cohorts in the specified contexts.
$cohortids = $DB->get_fieldset_select('cohort', 'id', $selectcontext, $contextparams);

if (empty($cohortids)) {
return;
}
$userid = $context->instanceid;

list($cohortsql, $cohortparams) = $DB->get_in_or_equal($cohortids, SQL_PARAMS_NAMED);
$selectcohort = "cohortid {$cohortsql} AND userid = :userid";
$params = ['userid' => $userid] + $cohortparams;

// Delete the tool_cohortroles records created for the userid.
$DB->delete_records('tool_cohortroles', ['userid' => $userid]);
$DB->delete_records_select('tool_cohortroles', $selectcohort, $params);
}

}
Loading

0 comments on commit a128601

Please sign in to comment.