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 /** 18 * Data provider. 19 * 20 * @package logstore_legacy 21 * @copyright 2018 Frédéric Massart 22 * @author Frédéric Massart <fred@branchup.tech> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace logstore_legacy\privacy; 27 defined('MOODLE_INTERNAL') || die(); 28 29 use context; 30 use core_privacy\local\metadata\collection; 31 use core_privacy\local\request\approved_contextlist; 32 use core_privacy\local\request\contextlist; 33 use core_privacy\local\request\transform; 34 use core_privacy\local\request\writer; 35 use tool_log\local\privacy\helper; 36 37 /** 38 * Data provider class. 39 * 40 * @package logstore_legacy 41 * @copyright 2018 Frédéric Massart 42 * @author Frédéric Massart <fred@branchup.tech> 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 class provider implements 46 \core_privacy\local\metadata\provider, 47 \tool_log\local\privacy\logstore_provider, 48 \tool_log\local\privacy\logstore_userlist_provider { 49 50 /** 51 * Returns metadata. 52 * 53 * @param collection $collection The initialised collection to add items to. 54 * @return collection A listing of user data stored through this system. 55 */ 56 public static function get_metadata(collection $collection) : collection { 57 $collection->add_external_location_link('log', [ 58 'time' => 'privacy:metadata:log:time', 59 'userid' => 'privacy:metadata:log:userid', 60 'ip' => 'privacy:metadata:log:ip', 61 'action' => 'privacy:metadata:log:action', 62 'url' => 'privacy:metadata:log:url', 63 'info' => 'privacy:metadata:log:info', 64 ], 'privacy:metadata:log'); 65 return $collection; 66 } 67 68 /** 69 * Add contexts that contain user information for the specified user. 70 * 71 * @param contextlist $contextlist The contextlist to add the contexts to. 72 * @param int $userid The user to find the contexts for. 73 * @return void 74 */ 75 public static function add_contexts_for_userid(contextlist $contextlist, $userid) { 76 $sql = " 77 SELECT ctx.id 78 FROM {context} ctx 79 JOIN {log} l 80 ON (l.cmid = 0 AND l.course = ctx.instanceid AND ctx.contextlevel = :courselevel) 81 OR (l.cmid > 0 AND l.cmid = ctx.instanceid AND ctx.contextlevel = :modulelevel) 82 OR (l.course <= 0 AND ctx.id = :syscontextid) 83 WHERE l.userid = :userid"; 84 $params = [ 85 'courselevel' => CONTEXT_COURSE, 86 'modulelevel' => CONTEXT_MODULE, 87 'syscontextid' => SYSCONTEXTID, 88 'userid' => $userid, 89 ]; 90 $contextlist->add_from_sql($sql, $params); 91 } 92 93 /** 94 * Add user IDs that contain user information for the specified context. 95 * 96 * @param \core_privacy\local\request\userlist $userlist The userlist to add the users to. 97 * @return void 98 */ 99 public static function add_userids_for_context(\core_privacy\local\request\userlist $userlist) { 100 $context = $userlist->get_context(); 101 list($insql, $params) = static::get_sql_where_from_contexts([$context]); 102 103 $sql = "SELECT l.userid 104 FROM {log} l 105 WHERE $insql"; 106 $userlist->add_from_sql('userid', $sql, $params); 107 } 108 109 /** 110 * Export all user data for the specified user, in the specified contexts. 111 * 112 * @param approved_contextlist $contextlist The approved contexts to export information for. 113 */ 114 public static function export_user_data(approved_contextlist $contextlist) { 115 global $DB; 116 117 $userid = $contextlist->get_user()->id; 118 list($insql, $inparams) = static::get_sql_where_from_contexts($contextlist->get_contexts()); 119 if (empty($insql)) { 120 return; 121 } 122 $sql = "userid = :userid AND $insql"; 123 $params = array_merge($inparams, ['userid' => $userid]); 124 125 $path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_legacy')]; 126 $flush = function($lastcontextid, $data) use ($path) { 127 $context = context::instance_by_id($lastcontextid); 128 writer::with_context($context)->export_data($path, (object) ['logs' => $data]); 129 }; 130 131 $lastcontextid = null; 132 $data = []; 133 $recordset = $DB->get_recordset_select('log', $sql, $params, 'course, cmid, time, id'); 134 foreach ($recordset as $record) { 135 $event = \logstore_legacy\event\legacy_logged::restore_legacy($record); 136 $context = $event->get_context(); 137 if ($lastcontextid && $lastcontextid != $context->id) { 138 $flush($lastcontextid, $data); 139 $data = []; 140 } 141 142 $extra = $event->get_logextra(); 143 $data[] = [ 144 'name' => $event->get_name(), 145 'description' => $event->get_description(), 146 'timecreated' => transform::datetime($event->timecreated), 147 'ip' => $extra['ip'], 148 'origin' => helper::transform_origin($extra['origin']), 149 ]; 150 151 $lastcontextid = $context->id; 152 } 153 if ($lastcontextid) { 154 $flush($lastcontextid, $data); 155 } 156 $recordset->close(); 157 } 158 159 /** 160 * Delete all data for all users in the specified context. 161 * 162 * @param context $context The specific context to delete data for. 163 */ 164 public static function delete_data_for_all_users_in_context(context $context) { 165 global $DB; 166 list($sql, $params) = static::get_sql_where_from_contexts([$context]); 167 if (empty($sql)) { 168 return; 169 } 170 $DB->delete_records_select('log', $sql, $params); 171 } 172 173 /** 174 * Delete all user data for the specified user, in the specified contexts. 175 * 176 * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. 177 */ 178 public static function delete_data_for_user(approved_contextlist $contextlist) { 179 global $DB; 180 list($sql, $params) = static::get_sql_where_from_contexts($contextlist->get_contexts()); 181 if (empty($sql)) { 182 return; 183 } 184 $userid = $contextlist->get_user()->id; 185 $DB->delete_records_select('log', "$sql AND userid = :userid", array_merge($params, ['userid' => $userid])); 186 } 187 188 189 /** 190 * Delete all data for a list of users in the specified context. 191 * 192 * @param \core_privacy\local\request\approved_userlist $userlist The specific context and users to delete data for. 193 * @return void 194 */ 195 public static function delete_data_for_userlist(\core_privacy\local\request\approved_userlist $userlist) { 196 global $DB; 197 list($sql, $params) = static::get_sql_where_from_contexts([$userlist->get_context()]); 198 if (empty($sql)) { 199 return; 200 } 201 list($usersql, $userparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED); 202 $params = array_merge($params, $userparams); 203 $DB->delete_records_select('log', "$sql AND userid $usersql", $params); 204 } 205 206 /** 207 * Get an SQL where statement from a list of contexts. 208 * 209 * @param array $contexts The contexts. 210 * @return array [$sql, $params] 211 */ 212 protected static function get_sql_where_from_contexts(array $contexts) { 213 global $DB; 214 215 $sorted = array_reduce($contexts, function ($carry, $context) { 216 $level = $context->contextlevel; 217 if ($level == CONTEXT_MODULE || $level == CONTEXT_COURSE) { 218 $carry[$level][] = $context->instanceid; 219 } else if ($level == CONTEXT_SYSTEM) { 220 $carry[$level] = $context->id; 221 } 222 return $carry; 223 }, [ 224 CONTEXT_COURSE => [], 225 CONTEXT_MODULE => [], 226 CONTEXT_SYSTEM => null, 227 ]); 228 229 $sqls = []; 230 $params = []; 231 232 if (!empty($sorted[CONTEXT_MODULE])) { 233 list($insql, $inparams) = $DB->get_in_or_equal($sorted[CONTEXT_MODULE], SQL_PARAMS_NAMED); 234 $sqls[] = "cmid $insql"; 235 $params = array_merge($params, $inparams); 236 } 237 238 if (!empty($sorted[CONTEXT_COURSE])) { 239 list($insql, $inparams) = $DB->get_in_or_equal($sorted[CONTEXT_COURSE], SQL_PARAMS_NAMED); 240 241 $sqls[] = "cmid = 0 AND course $insql"; 242 $params = array_merge($params, $inparams); 243 } 244 245 if (!empty($sorted[CONTEXT_SYSTEM])) { 246 $sqls[] = "course <= 0"; 247 } 248 249 if (empty($sqls)) { 250 return [null, null]; 251 } 252 253 return ['((' . implode(') OR (', $sqls) . '))', $params]; 254 } 255 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body