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 core_notes. 19 * 20 * @package core_notes 21 * @copyright 2018 Zig Tan <zig@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace core_notes\privacy; 26 27 use core_privacy\local\metadata\collection; 28 use core_privacy\local\request\approved_contextlist; 29 use core_privacy\local\request\contextlist; 30 use core_privacy\local\request\transform; 31 use core_privacy\local\request\writer; 32 use core_privacy\local\request\userlist; 33 use \core_privacy\local\request\approved_userlist; 34 35 defined('MOODLE_INTERNAL') || die(); 36 37 global $CFG; 38 require_once($CFG->dirroot . '/notes/lib.php'); 39 40 /** 41 * Implementation of the privacy subsystem plugin provider for core_notes. 42 * 43 * @copyright 2018 Zig Tan <zig@moodle.com> 44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 */ 46 class provider implements 47 \core_privacy\local\metadata\provider, 48 \core_privacy\local\request\core_userlist_provider, 49 \core_privacy\local\request\plugin\provider { 50 51 /** 52 * Return the fields which contain personal data. 53 * 54 * @param collection $items a reference to the collection to use to store the metadata. 55 * @return collection the updated collection of metadata items. 56 */ 57 public static function get_metadata(collection $items) : collection { 58 // The core_notes components utilises the shared mdl_post table. 59 $items->add_database_table( 60 'post', 61 [ 62 'content' => 'privacy:metadata:core_notes:content', 63 'courseid' => 'privacy:metadata:core_notes:courseid', 64 'created' => 'privacy:metadata:core_notes:created', 65 'lastmodified' => 'privacy:metadata:core_notes:lastmodified', 66 'publishstate' => 'privacy:metadata:core_notes:publishstate', 67 'userid' => 'privacy:metadata:core_notes:userid' 68 ], 69 'privacy:metadata:core_notes' 70 ); 71 72 return $items; 73 } 74 75 /** 76 * Get the list of contexts that contain user information for the specified user. 77 * 78 * @param int $userid the userid. 79 * @return contextlist the list of contexts containing user info for the user. 80 */ 81 public static function get_contexts_for_userid(int $userid) : contextlist { 82 global $DB; 83 84 $contextlist = new contextlist(); 85 86 $publishstates = [ 87 NOTES_STATE_PUBLIC, 88 NOTES_STATE_SITE 89 ]; 90 list($publishstatesql, $publishstateparams) = $DB->get_in_or_equal($publishstates, SQL_PARAMS_NAMED); 91 92 // Retrieve all the Course contexts associated with notes written by the user, and also written about the user. 93 // Only notes written about the user that are public or site wide will be exported. 94 $sql = "SELECT c.id 95 FROM {context} c 96 INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcoursewrittenby 97 WHERE p.module = 'notes' 98 AND p.usermodified = :usermodified 99 UNION 100 SELECT c.id 101 FROM {context} c 102 INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcoursewrittenfor 103 WHERE p.module = 'notes' 104 AND p.userid = :userid 105 AND p.publishstate {$publishstatesql}"; 106 107 $params = [ 108 'contextcoursewrittenby' => CONTEXT_COURSE, 109 'usermodified' => $userid, 110 'contextcoursewrittenfor' => CONTEXT_COURSE, 111 'userid' => $userid 112 ]; 113 $params += $publishstateparams; 114 115 $contextlist->add_from_sql($sql, $params); 116 117 return $contextlist; 118 } 119 120 /** 121 * Get the list of users who have data within a context. 122 * 123 * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. 124 */ 125 public static function get_users_in_context(userlist $userlist) { 126 global $DB; 127 128 $context = $userlist->get_context(); 129 130 if (!$context instanceof \context_course) { 131 return; 132 } 133 134 $params = [ 135 'instanceid' => $context->instanceid 136 ]; 137 138 $sql = "SELECT usermodified as userid 139 FROM {post} 140 WHERE module = 'notes' 141 AND courseid = :instanceid"; 142 143 $userlist->add_from_sql('userid', $sql, $params); 144 145 $publishstates = [ 146 NOTES_STATE_PUBLIC, 147 NOTES_STATE_SITE 148 ]; 149 150 list($publishstatesql, $publishstateparams) = $DB->get_in_or_equal($publishstates, SQL_PARAMS_NAMED); 151 $params += $publishstateparams; 152 153 $sql = "SELECT userid 154 FROM {post} 155 WHERE module = 'notes' 156 AND courseid = :instanceid 157 AND publishstate {$publishstatesql}"; 158 159 $userlist->add_from_sql('userid', $sql, $params); 160 } 161 162 /** 163 * Export personal data for the given approved_contextlist. 164 * User and context information is contained within the contextlist. 165 * 166 * @param approved_contextlist $contextlist a list of contexts approved for export. 167 */ 168 public static function export_user_data(approved_contextlist $contextlist) { 169 global $DB; 170 171 if (empty($contextlist->count())) { 172 return; 173 } 174 175 $userid = $contextlist->get_user()->id; 176 177 list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED); 178 179 // Export all notes written by and written about the user, and organize it by the associated Course context(s). 180 $sql = "SELECT p.courseid as courseid, 181 p.content as content, 182 p.publishstate as publishstate, 183 p.userid as userid, 184 p.usermodified as usermodified, 185 p.created as datecreated, 186 p.lastmodified as datemodified 187 FROM {context} c 188 INNER JOIN {post} p ON p.courseid = c.instanceid AND c.contextlevel = :contextcourse 189 WHERE p.module = 'notes' 190 AND (p.usermodified = :usermodified OR p.userid = :userid) 191 AND c.id {$contextsql}"; 192 193 $params = [ 194 'contextcourse' => CONTEXT_COURSE, 195 'usermodified' => $userid, 196 'userid' => $userid 197 ]; 198 $params += $contextparams; 199 200 $notes = $DB->get_recordset_sql($sql, $params); 201 foreach ($notes as $note) { 202 $contextcourse = \context_course::instance($note->courseid); 203 204 // The exported notes will be organized in {Course Context}/Notes/{publishstate}/usernote-{userid}.json. 205 $subcontext = [ 206 get_string('notes', 'notes'), 207 $note->publishstate 208 ]; 209 210 $name = 'usernote-' . transform::user($note->userid); 211 212 $notecontent = (object) [ 213 'content' => $note->content, 214 'publishstate' => $note->publishstate, 215 'userid' => transform::user($note->userid), 216 'usermodified' => transform::user($note->usermodified), 217 'datecreated' => transform::datetime($note->datecreated), 218 'datemodified' => transform::datetime($note->datemodified) 219 ]; 220 221 writer::with_context($contextcourse)->export_related_data($subcontext, $name, $notecontent); 222 } 223 $notes->close(); 224 } 225 226 /** 227 * Delete all data for all users in the specified context. 228 * 229 * @param \context $context the context to delete in. 230 */ 231 public static function delete_data_for_all_users_in_context(\context $context) { 232 global $DB; 233 234 if ($context->contextlevel != CONTEXT_COURSE) { 235 return; 236 } 237 238 $DB->delete_records('post', ['module' => 'notes', 'courseid' => $context->instanceid]); 239 } 240 241 /** 242 * Delete multiple users within a single context. 243 * 244 * @param approved_userlist $userlist The approved context and user information to delete information for. 245 */ 246 public static function delete_data_for_users(approved_userlist $userlist) { 247 global $DB; 248 249 $context = $userlist->get_context(); 250 if ($context->contextlevel != CONTEXT_COURSE) { 251 return; 252 } 253 254 $userids = $userlist->get_userids(); 255 if (empty($userids)) { 256 return; 257 } 258 259 list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); 260 $select = "module = :module AND courseid = :courseid AND usermodified {$usersql}"; 261 $params = ['module' => 'notes', 'courseid' => $context->instanceid] + $userparams; 262 263 $DB->delete_records_select('post', $select, $params); 264 } 265 266 /** 267 * Delete all user data for the specified user, in the specified contexts. 268 * 269 * @param approved_contextlist $contextlist a list of contexts approved for deletion. 270 */ 271 public static function delete_data_for_user(approved_contextlist $contextlist) { 272 global $DB; 273 274 if (empty($contextlist->count())) { 275 return; 276 } 277 278 $userid = $contextlist->get_user()->id; 279 280 foreach ($contextlist->get_contexts() as $context) { 281 $conditions = [ 282 'module' => 'notes', 283 'courseid' => $context->instanceid, 284 'usermodified' => $userid 285 ]; 286 287 $DB->delete_records('post', $conditions); 288 } 289 } 290 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body