See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 402] [Versions 401 and 403]
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 * Privacy Subsystem implementation for quizaccess_seb. 19 * 20 * @package quizaccess_seb 21 * @author Andrew Madden <andrewmadden@catalyst-au.net> 22 * @copyright 2019 Catalyst IT 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace quizaccess_seb\privacy; 27 28 use context; 29 use core_privacy\local\metadata\collection; 30 use core_privacy\local\request\approved_contextlist; 31 use core_privacy\local\request\approved_userlist; 32 use core_privacy\local\request\contextlist; 33 use core_privacy\local\request\transform; 34 use core_privacy\local\request\userlist; 35 use core_privacy\local\request\writer; 36 use quizaccess_seb\quiz_settings; 37 use quizaccess_seb\template; 38 39 defined('MOODLE_INTERNAL') || die(); 40 41 /** 42 * Privacy Subsystem implementation for quizaccess_seb. 43 * 44 * @copyright 2020 Catalyst IT 45 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 46 */ 47 class provider implements 48 \core_privacy\local\metadata\provider, 49 \core_privacy\local\request\core_userlist_provider, 50 \core_privacy\local\request\plugin\provider { 51 52 /** 53 * Retrieve the user metadata stored by plugin. 54 * 55 * @param collection $collection Collection of metadata. 56 * @return collection Collection of metadata. 57 */ 58 public static function get_metadata(collection $collection): collection { 59 $collection->add_database_table( 60 'quizaccess_seb_quizsettings', 61 [ 62 'quizid' => 'privacy:metadata:quizaccess_seb_quizsettings:quizid', 63 'usermodified' => 'privacy:metadata:quizaccess_seb_quizsettings:usermodified', 64 'timecreated' => 'privacy:metadata:quizaccess_seb_quizsettings:timecreated', 65 'timemodified' => 'privacy:metadata:quizaccess_seb_quizsettings:timemodified', 66 ], 67 'privacy:metadata:quizaccess_seb_quizsettings' 68 ); 69 70 $collection->add_database_table( 71 'quizaccess_seb_template', 72 [ 73 'usermodified' => 'privacy:metadata:quizaccess_seb_template:usermodified', 74 'timecreated' => 'privacy:metadata:quizaccess_seb_template:timecreated', 75 'timemodified' => 'privacy:metadata:quizaccess_seb_template:timemodified', 76 ], 77 'privacy:metadata:quizaccess_seb_template' 78 ); 79 80 return $collection; 81 } 82 83 /** 84 * Get the list of contexts that contain user information for the specified user. 85 * 86 * @param int $userid The user to search. 87 * @return contextlist A list of contexts used in this plugin. 88 */ 89 public static function get_contexts_for_userid(int $userid): contextlist { 90 $contextlist = new contextlist(); 91 92 // The data is associated at the module context level, so retrieve the quiz context id. 93 $sql = "SELECT c.id 94 FROM {quizaccess_seb_quizsettings} qs 95 JOIN {course_modules} cm ON cm.instance = qs.quizid 96 JOIN {modules} m ON cm.module = m.id AND m.name = :modulename 97 JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :context 98 WHERE qs.usermodified = :userid 99 GROUP BY c.id"; 100 101 $params = [ 102 'context' => CONTEXT_MODULE, 103 'modulename' => 'quiz', 104 'userid' => $userid 105 ]; 106 107 $contextlist->add_from_sql($sql, $params); 108 109 $sql = "SELECT c.id 110 FROM {quizaccess_seb_template} tem 111 JOIN {quizaccess_seb_quizsettings} qs ON qs.templateid = tem.id 112 JOIN {course_modules} cm ON cm.instance = qs.quizid 113 JOIN {modules} m ON cm.module = m.id AND m.name = :modulename 114 JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :context 115 WHERE qs.usermodified = :userid 116 GROUP BY c.id"; 117 118 $contextlist->add_from_sql($sql, $params); 119 120 return $contextlist; 121 } 122 123 /** 124 * Export all user data for the specified user, in the specified contexts. 125 * 126 * @param approved_contextlist $contextlist The approved contexts to export information for. 127 */ 128 public static function export_user_data(approved_contextlist $contextlist) { 129 global $DB; 130 131 // Get all cmids that correspond to the contexts for a user. 132 $cmids = []; 133 foreach ($contextlist->get_contexts() as $context) { 134 if ($context->contextlevel === CONTEXT_MODULE) { 135 $cmids[] = $context->instanceid; 136 } 137 } 138 139 // Do nothing if no matching quiz settings are found for the user. 140 if (empty($cmids)) { 141 return; 142 } 143 144 list($insql, $params) = $DB->get_in_or_equal($cmids, SQL_PARAMS_NAMED); 145 $params['modulename'] = 'quiz'; 146 147 // SEB quiz settings. 148 $sql = "SELECT qs.id as id, 149 qs.quizid as quizid, 150 qs.usermodified as usermodified, 151 qs.timecreated as timecreated, 152 qs.timemodified as timemodified 153 FROM {quizaccess_seb_quizsettings} qs 154 JOIN {course_modules} cm ON cm.instance = qs.quizid 155 JOIN {modules} m ON cm.module = m.id AND m.name = :modulename 156 WHERE cm.id {$insql}"; 157 158 $quizsettingslist = $DB->get_records_sql($sql, $params); 159 $index = 0; 160 foreach ($quizsettingslist as $quizsettings) { 161 // Data export is organised in: {Context}/{Plugin Name}/{Table name}/{index}/data.json. 162 $index++; 163 $subcontext = [ 164 get_string('pluginname', 'quizaccess_seb'), 165 quiz_settings::TABLE, 166 $index 167 ]; 168 169 $data = (object) [ 170 'quizid' => $quizsettings->quizid, 171 'usermodified' => $quizsettings->usermodified, 172 'timecreated' => transform::datetime($quizsettings->timecreated), 173 'timemodified' => transform::datetime($quizsettings->timemodified) 174 ]; 175 176 writer::with_context($context)->export_data($subcontext, $data); 177 } 178 179 // SEB template settings. 180 $sql = "SELECT tem.id as id, 181 qs.quizid as quizid, 182 tem.usermodified as usermodified, 183 tem.timecreated as timecreated, 184 tem.timemodified as timemodified 185 FROM {quizaccess_seb_template} tem 186 JOIN {quizaccess_seb_quizsettings} qs ON qs.templateid = tem.id 187 JOIN {course_modules} cm ON cm.instance = qs.quizid 188 JOIN {modules} m ON cm.module = m.id AND m.name = :modulename 189 WHERE cm.id {$insql}"; 190 191 $templatesettingslist = $DB->get_records_sql($sql, $params); 192 $index = 0; 193 foreach ($templatesettingslist as $templatesetting) { 194 // Data export is organised in: {Context}/{Plugin Name}/{Table name}/{index}/data.json. 195 $index++; 196 $subcontext = [ 197 get_string('pluginname', 'quizaccess_seb'), 198 template::TABLE, 199 $index 200 ]; 201 202 $data = (object) [ 203 'templateid' => $templatesetting->id, 204 'quizid' => $templatesetting->quizid, 205 'usermodified' => $templatesetting->usermodified, 206 'timecreated' => transform::datetime($templatesetting->timecreated), 207 'timemodified' => transform::datetime($templatesetting->timemodified) 208 ]; 209 210 writer::with_context($context)->export_data($subcontext, $data); 211 } 212 } 213 214 /** 215 * Delete all data for all users in the specified context. 216 * 217 * @param context $context The specific context to delete data for. 218 */ 219 public static function delete_data_for_all_users_in_context(\context $context) { 220 global $DB; 221 222 // Sanity check that context is at the module context level, then get the quizid. 223 if ($context->contextlevel !== CONTEXT_MODULE) { 224 return; 225 } 226 227 $cmid = $context->instanceid; 228 $quizid = $DB->get_field('course_modules', 'instance', ['id' => $cmid]); 229 230 $params['quizid'] = $quizid; 231 $select = "id IN (SELECT templateid FROM {quizaccess_seb_quizsettings} qs WHERE qs.quizid = :quizid)"; 232 $DB->set_field_select('quizaccess_seb_quizsettings', 'usermodified', 0, "quizid = :quizid", $params); 233 $DB->set_field_select('quizaccess_seb_template', 'usermodified', 0, $select, $params); 234 } 235 236 /** 237 * Delete all user data for the specified user, in the specified contexts. 238 * 239 * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. 240 */ 241 public static function delete_data_for_user(approved_contextlist $contextlist) { 242 global $DB; 243 244 // If the user has data, then only the User context should be present so get the first context. 245 $contexts = $contextlist->get_contexts(); 246 if (count($contexts) == 0) { 247 return; 248 } 249 250 $params['usermodified'] = $contextlist->get_user()->id; 251 $DB->set_field_select('quizaccess_seb_quizsettings', 'usermodified', 0, "usermodified = :usermodified", $params); 252 $DB->set_field_select('quizaccess_seb_template', 'usermodified', 0, "usermodified = :usermodified", $params); 253 } 254 255 /** 256 * Get the list of users who have data within a context. 257 * 258 * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. 259 */ 260 public static function get_users_in_context(userlist $userlist) { 261 $context = $userlist->get_context(); 262 263 if (!$context instanceof \context_module) { 264 return; 265 } 266 267 // The data is associated at the quiz module context level, so retrieve the user's context id. 268 $sql = "SELECT qs.usermodified AS userid 269 FROM {quizaccess_seb_quizsettings} qs 270 JOIN {course_modules} cm ON cm.instance = qs.quizid 271 JOIN {modules} m ON cm.module = m.id AND m.name = ? 272 WHERE cm.id = ?"; 273 $params = ['quiz', $context->instanceid]; 274 $userlist->add_from_sql('userid', $sql, $params); 275 } 276 277 /** 278 * Delete multiple users within a single context. 279 * 280 * @param approved_userlist $userlist The approved context and user information to delete information for. 281 */ 282 public static function delete_data_for_users(approved_userlist $userlist) { 283 global $DB; 284 $context = $userlist->get_context(); 285 286 // Sanity check that context is at the Module context level. 287 if ($context->contextlevel !== CONTEXT_MODULE) { 288 return; 289 } 290 291 $userids = $userlist->get_userids(); 292 list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); 293 294 $DB->set_field_select('quizaccess_seb_quizsettings', 'usermodified', 0, "usermodified {$insql}", $inparams); 295 $DB->set_field_select('quizaccess_seb_template', 'usermodified', 0, "usermodified {$insql}", $inparams); 296 } 297 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body