See Release Notes
Long Term Support Release
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 /** 17 * Privacy Subsystem implementation for enrol_lti. 18 * 19 * @package enrol_lti 20 * @category privacy 21 * @copyright 2018 Mark Nelson <markn@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace enrol_lti\privacy; 26 27 use core_privacy\local\metadata\collection; 28 use core_privacy\local\request\approved_contextlist; 29 use core_privacy\local\request\approved_userlist; 30 use core_privacy\local\request\contextlist; 31 use core_privacy\local\request\transform; 32 use core_privacy\local\request\userlist; 33 use core_privacy\local\request\writer; 34 35 defined('MOODLE_INTERNAL') || die(); 36 37 /** 38 * Privacy Subsystem for enrol_lti. 39 * 40 * @copyright 2018 Mark Nelson <markn@moodle.com> 41 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 42 */ 43 class provider implements 44 \core_privacy\local\metadata\provider, 45 \core_privacy\local\request\plugin\provider, 46 \core_privacy\local\request\core_userlist_provider { 47 48 /** 49 * Return the fields which contain personal data. 50 * 51 * @param collection $items a reference to the collection to use to store the metadata. 52 * @return collection the updated collection of metadata items. 53 */ 54 public static function get_metadata(collection $items) : collection { 55 $items->add_database_table( 56 'enrol_lti_users', 57 [ 58 'userid' => 'privacy:metadata:enrol_lti_users:userid', 59 'lastgrade' => 'privacy:metadata:enrol_lti_users:lastgrade', 60 'lastaccess' => 'privacy:metadata:enrol_lti_users:lastaccess', 61 'timecreated' => 'privacy:metadata:enrol_lti_users:timecreated' 62 ], 63 'privacy:metadata:enrol_lti_users' 64 ); 65 66 return $items; 67 } 68 69 /** 70 * Get the list of contexts that contain user information for the specified user. 71 * 72 * @param int $userid The user to search. 73 * @return contextlist The contextlist containing the list of contexts used in this plugin. 74 */ 75 public static function get_contexts_for_userid(int $userid) : contextlist { 76 $contextlist = new contextlist(); 77 78 $sql = "SELECT DISTINCT ctx.id 79 FROM {enrol_lti_users} ltiusers 80 JOIN {enrol_lti_tools} ltitools 81 ON ltiusers.toolid = ltitools.id 82 JOIN {context} ctx 83 ON ctx.id = ltitools.contextid 84 WHERE ltiusers.userid = :userid"; 85 $params = ['userid' => $userid]; 86 $contextlist->add_from_sql($sql, $params); 87 88 return $contextlist; 89 } 90 91 /** 92 * Get the list of users who have data within a context. 93 * 94 * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. 95 */ 96 public static function get_users_in_context(userlist $userlist) { 97 $context = $userlist->get_context(); 98 99 if (!($context instanceof \context_course || $context instanceof \context_module)) { 100 return; 101 } 102 103 $sql = "SELECT ltiusers.userid 104 FROM {enrol_lti_users} ltiusers 105 JOIN {enrol_lti_tools} ltitools ON ltiusers.toolid = ltitools.id 106 WHERE ltitools.contextid = :contextid"; 107 $params = ['contextid' => $context->id]; 108 $userlist->add_from_sql('userid', $sql, $params); 109 } 110 111 /** 112 * Export all user data for the specified user, in the specified contexts. 113 * 114 * @param approved_contextlist $contextlist The approved contexts to export information for. 115 */ 116 public static function export_user_data(approved_contextlist $contextlist) { 117 global $DB; 118 119 if (empty($contextlist->count())) { 120 return; 121 } 122 123 $user = $contextlist->get_user(); 124 125 list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED); 126 127 $sql = "SELECT ltiusers.lastgrade, ltiusers.lastaccess, ltiusers.timecreated, ltitools.contextid 128 FROM {enrol_lti_users} ltiusers 129 JOIN {enrol_lti_tools} ltitools 130 ON ltiusers.toolid = ltitools.id 131 JOIN {context} ctx 132 ON ctx.id = ltitools.contextid 133 WHERE ctx.id {$contextsql} 134 AND ltiusers.userid = :userid"; 135 $params = $contextparams + ['userid' => $user->id]; 136 $ltiusers = $DB->get_recordset_sql($sql, $params); 137 self::recordset_loop_and_export($ltiusers, 'contextid', [], function($carry, $record) { 138 $carry[] = [ 139 'lastgrade' => $record->lastgrade, 140 'timecreated' => transform::datetime($record->lastaccess), 141 'timemodified' => transform::datetime($record->timecreated) 142 ]; 143 return $carry; 144 }, function($contextid, $data) { 145 $context = \context::instance_by_id($contextid); 146 $finaldata = (object) $data; 147 writer::with_context($context)->export_data(['enrol_lti_users'], $finaldata); 148 }); 149 } 150 151 /** 152 * Delete all user data which matches the specified context. 153 * 154 * @param \context $context A user context. 155 */ 156 public static function delete_data_for_all_users_in_context(\context $context) { 157 global $DB; 158 159 if (!($context instanceof \context_course || $context instanceof \context_module)) { 160 return; 161 } 162 163 $enrolltitools = $DB->get_fieldset_select('enrol_lti_tools', 'id', 'contextid = :contextid', 164 ['contextid' => $context->id]); 165 if (!empty($enrolltitools)) { 166 list($sql, $params) = $DB->get_in_or_equal($enrolltitools, SQL_PARAMS_NAMED); 167 $DB->delete_records_select('enrol_lti_users', 'toolid ' . $sql, $params); 168 } 169 } 170 171 /** 172 * Delete all user data for the specified user, in the specified contexts. 173 * 174 * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. 175 */ 176 public static function delete_data_for_user(approved_contextlist $contextlist) { 177 global $DB; 178 179 $userid = $contextlist->get_user()->id; 180 181 foreach ($contextlist->get_contexts() as $context) { 182 if (!($context instanceof \context_course || $context instanceof \context_module)) { 183 continue; 184 } 185 186 $enrolltitools = $DB->get_fieldset_select('enrol_lti_tools', 'id', 'contextid = :contextid', 187 ['contextid' => $context->id]); 188 if (!empty($enrolltitools)) { 189 list($sql, $params) = $DB->get_in_or_equal($enrolltitools, SQL_PARAMS_NAMED); 190 $params = array_merge($params, ['userid' => $userid]); 191 $DB->delete_records_select('enrol_lti_users', "toolid $sql AND userid = :userid", $params); 192 } 193 } 194 } 195 196 /** 197 * Delete multiple users within a single context. 198 * 199 * @param approved_userlist $userlist The approved context and user information to delete information for. 200 */ 201 public static function delete_data_for_users(approved_userlist $userlist) { 202 global $DB; 203 204 $context = $userlist->get_context(); 205 206 if (!($context instanceof \context_course || $context instanceof \context_module)) { 207 return; 208 } 209 210 $enrolltitools = $DB->get_fieldset_select('enrol_lti_tools', 'id', 'contextid = :contextid', 211 ['contextid' => $context->id]); 212 if (!empty($enrolltitools)) { 213 list($toolsql, $toolparams) = $DB->get_in_or_equal($enrolltitools, SQL_PARAMS_NAMED); 214 $userids = $userlist->get_userids(); 215 list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); 216 $params = $toolparams + $userparams; 217 $DB->delete_records_select('enrol_lti_users', "toolid $toolsql AND userid $usersql", $params); 218 } 219 } 220 221 /** 222 * Loop and export from a recordset. 223 * 224 * @param \moodle_recordset $recordset The recordset. 225 * @param string $splitkey The record key to determine when to export. 226 * @param mixed $initial The initial data to reduce from. 227 * @param callable $reducer The function to return the dataset, receives current dataset, and the current record. 228 * @param callable $export The function to export the dataset, receives the last value from $splitkey and the dataset. 229 * @return void 230 */ 231 protected static function recordset_loop_and_export(\moodle_recordset $recordset, $splitkey, $initial, 232 callable $reducer, callable $export) { 233 $data = $initial; 234 $lastid = null; 235 236 foreach ($recordset as $record) { 237 if ($lastid && $record->{$splitkey} != $lastid) { 238 $export($lastid, $data); 239 $data = $initial; 240 } 241 $data = $reducer($data, $record); 242 $lastid = $record->{$splitkey}; 243 } 244 $recordset->close(); 245 246 if (!empty($lastid)) { 247 $export($lastid, $data); 248 } 249 } 250 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body