See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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 class for requesting user data. 19 * 20 * @package core_grading 21 * @copyright 2018 Sara Arjona <sara@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace core_grading\privacy; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 use \core_privacy\local\metadata\collection; 30 use \core_privacy\local\request\approved_contextlist; 31 use \core_privacy\local\request\contextlist; 32 use \core_privacy\local\request\transform; 33 use \core_privacy\local\request\writer; 34 use \core_privacy\manager; 35 36 /** 37 * Privacy class for requesting user data. 38 * 39 * @copyright 2018 Sara Arjona <sara@moodle.com> 40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 */ 42 class provider implements 43 \core_privacy\local\metadata\provider, 44 \core_privacy\local\request\plugin\provider, 45 \core_privacy\local\request\core_userlist_provider, 46 \core_privacy\local\request\subsystem\provider { 47 48 /** 49 * Returns meta data about this system. 50 * 51 * @param collection $collection The initialised collection to add items to. 52 * @return collection A listing of user data stored through this system. 53 */ 54 public static function get_metadata(collection $collection) : collection { 55 $collection->add_database_table('grading_definitions', [ 56 'method' => 'privacy:metadata:grading_definitions:method', 57 'areaid' => 'privacy:metadata:grading_definitions:areaid', 58 'name' => 'privacy:metadata:grading_definitions:name', 59 'description' => 'privacy:metadata:grading_definitions:description', 60 'status' => 'privacy:metadata:grading_definitions:status', 61 'copiedfromid' => 'privacy:metadata:grading_definitions:copiedfromid', 62 'timecopied' => 'privacy:metadata:grading_definitions:timecopied', 63 'timecreated' => 'privacy:metadata:grading_definitions:timecreated', 64 'usercreated' => 'privacy:metadata:grading_definitions:usercreated', 65 'timemodified' => 'privacy:metadata:grading_definitions:timemodified', 66 'usermodified' => 'privacy:metadata:grading_definitions:usermodified', 67 'options' => 'privacy:metadata:grading_definitions:options', 68 ], 'privacy:metadata:grading_definitions'); 69 70 $collection->add_database_table('grading_instances', [ 71 'raterid' => 'privacy:metadata:grading_instances:raterid', 72 'rawgrade' => 'privacy:metadata:grading_instances:rawgrade', 73 'status' => 'privacy:metadata:grading_instances:status', 74 'feedback' => 'privacy:metadata:grading_instances:feedback', 75 'feedbackformat' => 'privacy:metadata:grading_instances:feedbackformat', 76 'timemodified' => 'privacy:metadata:grading_instances:timemodified', 77 ], 'privacy:metadata:grading_instances'); 78 79 // Link to subplugin. 80 $collection->add_plugintype_link('gradingform', [], 'privacy:metadata:gradingformpluginsummary'); 81 82 return $collection; 83 } 84 85 /** 86 * Get the list of contexts that contain user information for the specified user. 87 * 88 * @param int $userid The user to search. 89 * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin. 90 */ 91 public static function get_contexts_for_userid(int $userid) : contextlist { 92 $contextlist = new contextlist(); 93 94 $sql = "SELECT c.id 95 FROM {context} c 96 JOIN {grading_areas} a ON a.contextid = c.id 97 JOIN {grading_definitions} d ON d.areaid = a.id 98 LEFT JOIN {grading_instances} i ON i.definitionid = d.id AND i.raterid = :raterid 99 WHERE c.contextlevel = :contextlevel 100 AND (d.usercreated = :usercreated OR d.usermodified = :usermodified OR i.id IS NOT NULL)"; 101 $params = [ 102 'usercreated' => $userid, 103 'usermodified' => $userid, 104 'raterid' => $userid, 105 'contextlevel' => CONTEXT_MODULE 106 ]; 107 $contextlist->add_from_sql($sql, $params); 108 109 return $contextlist; 110 } 111 112 /** 113 * Get the list of users who have data within a context. 114 * 115 * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. 116 */ 117 public static function get_users_in_context(\core_privacy\local\request\userlist $userlist) { 118 $context = $userlist->get_context(); 119 if ($context->contextlevel != CONTEXT_MODULE) { 120 return; 121 } 122 123 $params = ['contextid' => $context->id]; 124 125 $sql = "SELECT d.usercreated, d.usermodified 126 FROM {grading_definitions} d 127 JOIN {grading_areas} a ON a.id = d.areaid 128 WHERE a.contextid = :contextid"; 129 $userlist->add_from_sql('usercreated', $sql, $params); 130 $userlist->add_from_sql('usermodified', $sql, $params); 131 132 $sql = "SELECT i.raterid 133 FROM {grading_definitions} d 134 JOIN {grading_areas} a ON a.id = d.areaid 135 JOIN {grading_instances} i ON i.definitionid = d.id 136 WHERE a.contextid = :contextid"; 137 $userlist->add_from_sql('raterid', $sql, $params); 138 } 139 140 /** 141 * Export all user data for the specified user, in the specified contexts. 142 * 143 * @param approved_contextlist $contextlist The approved contexts to export information for. 144 */ 145 public static function export_user_data(approved_contextlist $contextlist) { 146 // Remove contexts different from MODULE. 147 $contexts = array_reduce($contextlist->get_contexts(), function($carry, $context) { 148 if ($context->contextlevel == CONTEXT_MODULE) { 149 $carry[] = $context; 150 } 151 return $carry; 152 }, []); 153 154 if (empty($contexts)) { 155 return; 156 } 157 158 $userid = $contextlist->get_user()->id; 159 $subcontext = [get_string('gradingmethod', 'grading')]; 160 foreach ($contexts as $context) { 161 // Export grading definitions created or modified on this context. 162 self::export_definitions($context, $subcontext, $userid); 163 } 164 } 165 166 /** 167 * Export all user data related to a context and itemid. 168 * 169 * @param \context $context Context to export on. 170 * @param int $itemid Item ID to export on. 171 * @param array $subcontext Directory location to export to. 172 */ 173 public static function export_item_data(\context $context, int $itemid, array $subcontext) { 174 global $DB; 175 176 $sql = "SELECT gi.id AS instanceid, gd.id AS definitionid, gd.method 177 FROM {grading_areas} ga 178 JOIN {grading_definitions} gd ON gd.areaid = ga.id 179 JOIN {grading_instances} gi ON gi.definitionid = gd.id AND gi.itemid = :itemid 180 WHERE ga.contextid = :contextid"; 181 $params = [ 182 'itemid' => $itemid, 183 'contextid' => $context->id, 184 ]; 185 $records = $DB->get_recordset_sql($sql, $params); 186 foreach ($records as $record) { 187 $instancedata = manager::component_class_callback( 188 "gradingform_{$record->method}", 189 gradingform_provider_v2::class, 190 'export_gradingform_instance_data', 191 [$context, $record->instanceid, $subcontext] 192 ); 193 } 194 $records->close(); 195 } 196 197 /** 198 * Deletes all user data related to a context and possibly an itemid. 199 * 200 * @param \context $context The context to delete on. 201 * @param int|null $itemid An optional item ID to refine the deletion. 202 */ 203 public static function delete_instance_data(\context $context, int $itemid = null) { 204 if (is_null($itemid)) { 205 self::delete_data_for_instances($context); 206 } else { 207 self::delete_data_for_instances($context, [$itemid]); 208 } 209 } 210 211 /** 212 * Deletes all user data related to a context and possibly itemids. 213 * 214 * @param \context $context The context to delete on. 215 * @param array $itemids An optional list of item IDs to refine the deletion. 216 */ 217 public static function delete_data_for_instances(\context $context, array $itemids = []) { 218 global $DB; 219 $itemsql = ''; 220 $params = ['contextid' => $context->id]; 221 if (!empty($itemids)) { 222 list($itemsql, $itemparams) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED); 223 $params = array_merge($params, $itemparams); 224 $itemsql = "AND itemid $itemsql"; 225 } 226 $sql = "SELECT gi.id AS instanceid, gd.id, gd.method 227 FROM {grading_definitions} gd 228 JOIN {grading_instances} gi ON gi.definitionid = gd.id 229 JOIN {grading_areas} ga ON ga.id = gd.areaid 230 WHERE ga.contextid = :contextid $itemsql"; 231 $records = $DB->get_records_sql($sql, $params); 232 if ($records) { 233 $firstrecord = current($records); 234 $method = $firstrecord->method; 235 $instanceids = array_map(function($record) { 236 return $record->instanceid; 237 }, $records); 238 manager::component_class_callback( 239 "gradingform_{$method}", 240 gradingform_provider_v2::class, 241 'delete_gradingform_for_instances', 242 [$instanceids]); 243 // Delete grading_instances rows. 244 $DB->delete_records_list('grading_instances', 'id', $instanceids); 245 } 246 } 247 248 /** 249 * Exports the data related to grading definitions within the specified context/subcontext. 250 * 251 * @param \context $context Context owner of the data. 252 * @param array $subcontext Subcontext owner of the data. 253 * @param int $userid The user whose information is to be exported. 254 */ 255 protected static function export_definitions(\context $context, array $subcontext, int $userid = 0) { 256 global $DB; 257 258 $join = "JOIN {grading_areas} a ON a.id = d.areaid 259 JOIN {context} c ON a.contextid = c.id AND c.contextlevel = :contextlevel"; 260 $select = 'a.contextid = :contextid'; 261 $params = [ 262 'contextlevel' => CONTEXT_MODULE, 263 'contextid' => $context->id 264 ]; 265 266 if (!empty($userid)) { 267 $join .= ' LEFT JOIN {grading_instances} i ON i.definitionid = d.id AND i.raterid = :raterid'; 268 $select .= ' AND (usercreated = :usercreated 269 OR usermodified = :usermodified OR i.id IS NOT NULL)'; 270 $params['usercreated'] = $userid; 271 $params['usermodified'] = $userid; 272 $params['raterid'] = $userid; 273 } 274 275 $sql = "SELECT gd.id, 276 gd.method, 277 gd.name, 278 gd.description, 279 gd.timecopied, 280 gd.timecreated, 281 gd.usercreated, 282 gd.timemodified, 283 gd.usermodified 284 FROM ( 285 SELECT DISTINCT d.id 286 FROM {grading_definitions} d 287 $join 288 WHERE $select 289 ) ids 290 JOIN {grading_definitions} gd ON gd.id = ids.id"; 291 $definitions = $DB->get_recordset_sql($sql, $params); 292 $defdata = []; 293 foreach ($definitions as $definition) { 294 $tmpdata = [ 295 'method' => $definition->method, 296 'name' => $definition->name, 297 'description' => $definition->description, 298 'timecreated' => transform::datetime($definition->timecreated), 299 'usercreated' => transform::user($definition->usercreated), 300 'timemodified' => transform::datetime($definition->timemodified), 301 'usermodified' => transform::user($definition->usermodified), 302 ]; 303 if (!empty($definition->timecopied)) { 304 $tmpdata['timecopied'] = transform::datetime($definition->timecopied); 305 } 306 307 // MDL-63167 - This section is to be removed with the final deprecation of the gradingform_provider interface. 308 // Export gradingform information (if needed). 309 $instancedata = manager::component_class_callback( 310 "gradingform_{$definition->method}", 311 gradingform_provider::class, 312 'get_gradingform_export_data', 313 [$context, $definition, $userid] 314 ); 315 if (null !== $instancedata) { 316 $tmpdata = array_merge($tmpdata, $instancedata); 317 } 318 // End of section to be removed with deprecation. 319 320 $defdata[] = (object) $tmpdata; 321 322 // Export grading_instances information. 323 self::export_grading_instances($context, $subcontext, $definition->id, $userid); 324 } 325 $definitions->close(); 326 327 if (!empty($defdata)) { 328 $data = (object) [ 329 'definitions' => $defdata, 330 ]; 331 332 writer::with_context($context)->export_data($subcontext, $data); 333 } 334 } 335 336 /** 337 * Exports the data related to grading instances within the specified definition. 338 * 339 * @param \context $context Context owner of the data. 340 * @param array $subcontext Subcontext owner of the data. 341 * @param int $definitionid The definition ID whose grading instance information is to be exported. 342 * @param int $userid The user whose information is to be exported. 343 */ 344 protected static function export_grading_instances(\context $context, array $subcontext, int $definitionid, int $userid = 0) { 345 global $DB; 346 347 $params = ['definitionid' => $definitionid]; 348 if (!empty($userid)) { 349 $params['raterid'] = $userid; 350 } 351 $instances = $DB->get_recordset('grading_instances', $params); 352 $instancedata = []; 353 foreach ($instances as $instance) { 354 // TODO: Get the status name (instead of the ID). 355 $tmpdata = [ 356 'rawgrade' => $instance->rawgrade, 357 'status' => $instance->status, 358 'feedback' => $instance->feedback, 359 'feedbackformat' => $instance->feedbackformat, 360 'timemodified' => transform::datetime($instance->timemodified), 361 ]; 362 $instancedata[] = (object) $tmpdata; 363 } 364 $instances->close(); 365 366 if (!empty($instancedata)) { 367 $data = (object) [ 368 'instances' => $instancedata, 369 ]; 370 371 writer::with_context($context)->export_related_data($subcontext, 'gradinginstances', $data); 372 } 373 } 374 375 /** 376 * No deletion of the advanced grading is done. 377 * 378 * @param \context $context the context to delete in. 379 */ 380 public static function delete_data_for_all_users_in_context(\context $context) { 381 // MDL-63167 - This section is to be removed with the final deprecation of the gradingform_provider interface. 382 manager::plugintype_class_callback( 383 'gradingform', 384 gradingform_provider::class, 385 'delete_gradingform_for_context', 386 [$context] 387 ); 388 // End of section to be removed for final deprecation. 389 } 390 391 /** 392 * Deletion of data in this provider is only related to grades and so can not be 393 * deleted for the creator of the advanced grade criteria. 394 * 395 * @param approved_contextlist $contextlist a list of contexts approved for deletion. 396 */ 397 public static function delete_data_for_user(approved_contextlist $contextlist) { 398 // MDL-63167 - This section is to be removed with the final deprecation of the gradingform_provider interface. 399 manager::plugintype_class_callback( 400 'gradingform', 401 gradingform_provider::class, 402 'delete_gradingform_for_userid', 403 [$contextlist] 404 ); 405 // End of section to be removed for final deprecation. 406 } 407 408 /** 409 * Delete multiple users within a single context. 410 * 411 * @param approved_userlist $userlist The approved context and user information to delete information for. 412 */ 413 public static function delete_data_for_users(\core_privacy\local\request\approved_userlist $userlist) { 414 // The only information left to be deleted here is the grading definitions. Currently we are not deleting these. 415 } 416 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body