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 tool_policy. 19 * 20 * @package tool_policy 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 tool_policy\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\moodle_content_writer; 32 use core_privacy\local\request\userlist; 33 use core_privacy\local\request\transform; 34 use core_privacy\local\request\writer; 35 36 defined('MOODLE_INTERNAL') || die(); 37 38 /** 39 * Implementation of the privacy subsystem plugin provider for the policy tool. 40 * 41 * @copyright 2018 Sara Arjona <sara@moodle.com> 42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 43 */ 44 class provider implements 45 // This tool stores user data. 46 \core_privacy\local\metadata\provider, 47 48 // This plugin is capable of determining which users have data within it. 49 \core_privacy\local\request\core_userlist_provider, 50 51 // This tool may provide access to and deletion of user data. 52 \core_privacy\local\request\plugin\provider { 53 54 /** 55 * Return the fields which contain personal data. 56 * 57 * @param collection $collection The initialised collection to add items to. 58 * @return collection A listing of user data stored through this system. 59 */ 60 public static function get_metadata(collection $collection) : collection { 61 $collection->add_database_table( 62 'tool_policy_acceptances', 63 [ 64 'policyversionid' => 'privacy:metadata:acceptances:policyversionid', 65 'userid' => 'privacy:metadata:acceptances:userid', 66 'status' => 'privacy:metadata:acceptances:status', 67 'lang' => 'privacy:metadata:acceptances:lang', 68 'usermodified' => 'privacy:metadata:acceptances:usermodified', 69 'timecreated' => 'privacy:metadata:acceptances:timecreated', 70 'timemodified' => 'privacy:metadata:acceptances:timemodified', 71 'note' => 'privacy:metadata:acceptances:note', 72 ], 73 'privacy:metadata:acceptances' 74 ); 75 76 $collection->add_database_table( 77 'tool_policy_versions', 78 [ 79 'name' => 'privacy:metadata:versions:name', 80 'type' => 'privacy:metadata:versions:type', 81 'audience' => 'privacy:metadata:versions:audience', 82 'archived' => 'privacy:metadata:versions:archived', 83 'usermodified' => 'privacy:metadata:versions:usermodified', 84 'timecreated' => 'privacy:metadata:versions:timecreated', 85 'timemodified' => 'privacy:metadata:versions:timemodified', 86 'policyid' => 'privacy:metadata:versions:policyid', 87 'revision' => 'privacy:metadata:versions:revision', 88 'summary' => 'privacy:metadata:versions:summary', 89 'summaryformat' => 'privacy:metadata:versions:summaryformat', 90 'content' => 'privacy:metadata:versions:content', 91 'contentformat' => 'privacy:metadata:versions:contentformat', 92 ], 93 'privacy:metadata:versions' 94 ); 95 96 $collection->add_subsystem_link('core_files', [], 'privacy:metadata:subsystem:corefiles'); 97 98 return $collection; 99 } 100 101 /** 102 * Get the list of contexts that contain user information for the specified user. 103 * 104 * @param int $userid The userid. 105 * @return contextlist The list of contexts containing user info for the user. 106 */ 107 public static function get_contexts_for_userid(int $userid) : contextlist { 108 $contextlist = new contextlist(); 109 110 // Policies a user has modified. 111 $sql = "SELECT c.id 112 FROM {context} c 113 JOIN {tool_policy_versions} v ON v.usermodified = :userid 114 WHERE c.contextlevel = :contextlevel"; 115 $params = [ 116 'contextlevel' => CONTEXT_SYSTEM, 117 'userid' => $userid, 118 ]; 119 $contextlist->add_from_sql($sql, $params); 120 121 // Policies a user has accepted. 122 $sql = "SELECT c.id 123 FROM {context} c 124 JOIN {tool_policy_acceptances} a ON c.instanceid = a.userid 125 WHERE 126 c.contextlevel = :contextlevel 127 AND ( 128 a.userid = :userid OR a.usermodified = :usermodified 129 )"; 130 $params = [ 131 'contextlevel' => CONTEXT_USER, 132 'userid' => $userid, 133 'usermodified' => $userid, 134 ]; 135 $contextlist->add_from_sql($sql, $params); 136 137 return $contextlist; 138 } 139 140 /** 141 * Get the list of users who have data within a context. 142 * 143 * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. 144 */ 145 public static function get_users_in_context(userlist $userlist) { 146 $context = $userlist->get_context(); 147 148 // Users that have modified any policies, if fetching for system context. 149 if (is_a($context, \context_system::class)) { 150 $sql = "SELECT v.usermodified AS userid 151 FROM {tool_policy_versions} v"; 152 $userlist->add_from_sql('userid', $sql, []); 153 } 154 155 // Users that have accepted any policies, if fetching for user context. 156 if (is_a($context, \context_user::class)) { 157 $sql = "SELECT a.userid, a.usermodified 158 FROM {tool_policy_acceptances} a 159 WHERE a.userid = :instanceid"; 160 $params = ['instanceid' => $context->instanceid]; 161 162 $userlist->add_from_sql('userid', $sql, $params); 163 $userlist->add_from_sql('usermodified', $sql, $params); 164 } 165 } 166 167 /** 168 * Export personal data for the given approved_contextlist. User and context information is contained within the contextlist. 169 * 170 * @param approved_contextlist $contextlist A list of contexts approved for export. 171 */ 172 public static function export_user_data(approved_contextlist $contextlist) { 173 global $DB; 174 175 // Export user agreements. 176 foreach ($contextlist->get_contexts() as $context) { 177 if ($context->contextlevel == CONTEXT_USER) { 178 static::export_policy_agreements_for_context($context); 179 } else if ($context->contextlevel == CONTEXT_SYSTEM) { 180 static::export_authored_policies($contextlist->get_user()); 181 } 182 } 183 } 184 185 /** 186 * Delete all data for all users in the specified context. 187 * 188 * We never delete user agreements to the policies because they are part of privacy data. 189 * We never delete policy versions because they are part of privacy data. 190 * 191 * @param \context $context The context to delete in. 192 */ 193 public static function delete_data_for_all_users_in_context(\context $context) { 194 } 195 196 /** 197 * Delete all user data for the specified user, in the specified contexts. 198 * 199 * We never delete user agreements to the policies because they are part of privacy data. 200 * We never delete policy versions because they are part of privacy data. 201 * 202 * @param approved_contextlist $contextlist A list of contexts approved for deletion. 203 */ 204 public static function delete_data_for_user(approved_contextlist $contextlist) { 205 } 206 207 /** 208 * Delete multiple users within a single context. 209 * 210 * We never delete user agreements to the policies because they are part of privacy data. 211 * We never delete policy versions because they are part of privacy data. 212 * 213 * @param approved_userlist $userlist The approved context and user information to delete information for. 214 */ 215 public static function delete_data_for_users(approved_userlist $userlist) { 216 } 217 218 /** 219 * Export all policy agreements relating to the specified user context. 220 * 221 * @param \context_user $context The context to export 222 */ 223 protected static function export_policy_agreements_for_context(\context_user $context) { 224 global $DB; 225 226 $sysctx = \context_system::instance(); 227 $fs = get_file_storage(); 228 $agreementsql = " 229 SELECT 230 a.id AS agreementid, a.userid, a.timemodified, a.note, a.status, 231 a.policyversionid AS versionid, a.usermodified, a.timecreated, 232 v.id, v.archived, v.name, v.revision, 233 v.summary, v.summaryformat, 234 v.content, v.contentformat, 235 p.currentversionid 236 FROM {tool_policy_acceptances} a 237 JOIN {tool_policy_versions} v ON v.id = a.policyversionid 238 JOIN {tool_policy} p ON v.policyid = p.id 239 WHERE a.userid = :userid OR a.usermodified = :usermodified"; 240 241 // Fetch all agreements related to this user. 242 $agreements = $DB->get_recordset_sql($agreementsql, [ 243 'userid' => $context->instanceid, 244 'usermodified' => $context->instanceid, 245 ]); 246 247 $basecontext = [ 248 get_string('privacyandpolicies', 'admin'), 249 get_string('useracceptances', 'tool_policy'), 250 ]; 251 252 foreach ($agreements as $agreement) { 253 $subcontext = array_merge($basecontext, [get_string('policynamedversion', 'tool_policy', $agreement)]); 254 255 $summary = writer::with_context($context)->rewrite_pluginfile_urls( 256 $subcontext, 257 'tool_policy', 258 'policydocumentsummary', 259 $agreement->versionid, 260 $agreement->summary 261 ); 262 $content = writer::with_context($context)->rewrite_pluginfile_urls( 263 $subcontext, 264 'tool_policy', 265 'policydocumentcontent', 266 $agreement->versionid, 267 $agreement->content 268 ); 269 $agreementcontent = (object) [ 270 'name' => $agreement->name, 271 'revision' => $agreement->revision, 272 'isactive' => transform::yesno($agreement->versionid == $agreement->currentversionid), 273 'isagreed' => transform::yesno($agreement->status), 274 'agreedby' => transform::user($agreement->usermodified), 275 'timecreated' => transform::datetime($agreement->timecreated), 276 'timemodified' => transform::datetime($agreement->timemodified), 277 'note' => $agreement->note, 278 'summary' => format_text($summary, $agreement->summaryformat), 279 'content' => format_text($content, $agreement->contentformat), 280 ]; 281 282 writer::with_context($context)->export_data($subcontext, $agreementcontent); 283 // Manually export the files as they reside in the system context so we can't use 284 // the write's helper methods. 285 foreach ($fs->get_area_files($sysctx->id, 'tool_policy', 'policydocumentsummary', $agreement->versionid) as $file) { 286 writer::with_context($context)->export_file($subcontext, $file); 287 } 288 foreach ($fs->get_area_files($sysctx->id, 'tool_policy', 'policydocumentcontent', $agreement->versionid) as $file) { 289 writer::with_context($context)->export_file($subcontext, $file); 290 } 291 } 292 $agreements->close(); 293 } 294 295 /** 296 * Export all policy agreements that the user authored. 297 * 298 * @param stdClass $user The user who has created the policies to export. 299 */ 300 protected static function export_authored_policies(\stdClass $user) { 301 global $DB; 302 303 // Authored policies are exported against the system. 304 $context = \context_system::instance(); 305 $basecontext = [ 306 get_string('policydocuments', 'tool_policy'), 307 ]; 308 309 $sql = "SELECT v.id, 310 v.name, 311 v.revision, 312 v.summary, 313 v.content, 314 v.archived, 315 v.usermodified, 316 v.timecreated, 317 v.timemodified, 318 p.currentversionid 319 FROM {tool_policy_versions} v 320 JOIN {tool_policy} p ON p.id = v.policyid 321 WHERE v.usermodified = :userid"; 322 $versions = $DB->get_recordset_sql($sql, ['userid' => $user->id]); 323 foreach ($versions as $version) { 324 $subcontext = array_merge($basecontext, [get_string('policynamedversion', 'tool_policy', $version)]); 325 326 $versioncontent = (object) [ 327 'name' => $version->name, 328 'revision' => $version->revision, 329 'summary' => writer::with_context($context)->rewrite_pluginfile_urls( 330 $subcontext, 331 'tool_policy', 332 'policydocumentsummary', 333 $version->id, 334 $version->summary 335 ), 336 'content' => writer::with_context($context)->rewrite_pluginfile_urls( 337 $subcontext, 338 'tool_policy', 339 'policydocumentcontent', 340 $version->id, 341 $version->content 342 ), 343 'isactive' => transform::yesno($version->id == $version->currentversionid), 344 'isarchived' => transform::yesno($version->archived), 345 'createdbyme' => transform::yesno($version->usermodified == $user->id), 346 'timecreated' => transform::datetime($version->timecreated), 347 'timemodified' => transform::datetime($version->timemodified), 348 ]; 349 writer::with_context($context) 350 ->export_data($subcontext, $versioncontent) 351 ->export_area_files($subcontext, 'tool_policy', 'policydocumentsummary', $version->id) 352 ->export_area_files($subcontext, 'tool_policy', 'policydocumentcontent', $version->id); 353 } 354 $versions->close(); 355 } 356 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body