MDL-63495 privacy: Add support for removal of multiple users in a context
[moodle.git] / privacy / classes / local / request / helper.php
blob9836e68b059df3d0e81fa613bb3a2f7fb34865a1
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.
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/>.
17 /**
18 * This file contains the core_privacy\local\request helper.
20 * @package core_privacy
21 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 namespace core_privacy\local\request;
27 use \core_privacy\local\request\writer;
29 defined('MOODLE_INTERNAL') || die();
31 require_once($CFG->libdir . '/modinfolib.php');
32 require_once($CFG->dirroot . '/course/modlib.php');
34 /**
35 * The core_privacy\local\request\helper class with useful shared functionality.
37 * @package core_privacy
38 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42 class helper {
44 /**
45 * Add core-controlled contexts which are related to a component but that component may know about.
47 * For example, most activities are not aware of activity completion, but the course implements it for them.
48 * These should be included.
50 * @param int $userid The user being added for.
51 * @param contextlist $contextlist The contextlist being appended to.
52 * @return contextlist The final contextlist
54 public static function add_shared_contexts_to_contextlist_for(int $userid, contextlist $contextlist) : contextlist {
55 if (strpos($contextlist->get_component(), 'mod_') === 0) {
56 // Activity modules support data stored by core about them - for example, activity completion.
57 $contextlist = static::add_shared_contexts_to_contextlist_for_course_module($userid, $contextlist);
60 return $contextlist;
63 /**
64 * Add core-controlled contexts which are related to a component but that component may know about.
66 * For example, most activities are not aware of activity completion, but the course implements it for them.
67 * These should be included.
69 * @param \core_privacy\local\request\userlist $userlist
70 * @return contextlist The final contextlist
72 public static function add_shared_users_to_userlist(\core_privacy\local\request\userlist $userlist) {
75 /**
76 * Handle export of standard data for a plugin which implements the null provider and does not normally store data
77 * of its own.
79 * This is used in cases such as activities like mod_resource, which do not store their own data, but may still have
80 * data on them (like Activity Completion).
82 * Any context provided in a contextlist should have base data exported as a minimum.
84 * @param approved_contextlist $contextlist The approved contexts to export information for.
86 public static function export_data_for_null_provider(approved_contextlist $contextlist) {
87 $user = $contextlist->get_user();
88 foreach ($contextlist as $context) {
89 $data = static::get_context_data($context, $user);
90 static::export_context_files($context, $user);
92 writer::with_context($context)->export_data([], $data);
96 /**
97 * Handle removal of 'standard' data for any plugin.
99 * This will handle deletion for things such as activity completion.
101 * @param string $component The component being deleted for.
102 * @param context $context The specific context to delete data for.
104 public static function delete_data_for_all_users_in_context(string $component, \context $context) {
105 // Activity modules support data stored by core about them - for example, activity completion.
106 static::delete_data_for_all_users_in_context_course_module($component, $context);
110 * Delete all 'standard' user data for the specified user, in the specified contexts.
112 * This will handle deletion for things such as activity completion.
114 * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
116 public static function delete_data_for_user(approved_contextlist $contextlist) {
117 $component = $contextlist->get_component();
119 // Activity modules support data stored by core about them - for example, activity completion.
120 static::delete_data_for_user_in_course_module($contextlist);
124 * Get all general data for this context.
126 * @param \context $context The context to retrieve data for.
127 * @param \stdClass $user The user being written.
128 * @return \stdClass
130 public static function get_context_data(\context $context, \stdClass $user) : \stdClass {
131 global $DB;
133 $basedata = (object) [];
134 if ($context instanceof \context_module) {
135 return static::get_context_module_data($context, $user);
137 if ($context instanceof \context_block) {
138 return static::get_context_block_data($context, $user);
141 return $basedata;
145 * Export all files for this context.
147 * @param \context $context The context to export files for.
148 * @param \stdClass $user The user being written.
149 * @return \stdClass
151 public static function export_context_files(\context $context, \stdClass $user) {
152 if ($context instanceof \context_module) {
153 return static::export_context_module_files($context, $user);
158 * Add core-controlled contexts which are related to a component but that component may know about.
160 * For example, most activities are not aware of activity completion, but the course implements it for them.
161 * These should be included.
163 * @param int $userid The user being added for.
164 * @param contextlist $contextlist The contextlist being appended to.
165 * @return contextlist The final contextlist
167 protected static function add_shared_contexts_to_contextlist_for_course_module(int $userid, contextlist $contextlist) : contextlist {
168 // Fetch all contexts where the user has activity completion enabled.
169 $sql = "SELECT
170 c.id
171 FROM {course_modules_completion} cmp
172 INNER JOIN {course_modules} cm ON cm.id = cmp.coursemoduleid
173 INNER JOIN {modules} m ON m.id = cm.module
174 INNER JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :contextlevel
175 WHERE cmp.userid = :userid
176 AND m.name = :modname";
177 $params = [
178 'userid' => $userid,
179 // Strip the mod_ from the name.
180 'modname' => substr($contextlist->get_component(), 4),
181 'contextlevel' => CONTEXT_MODULE,
184 $contextlist->add_from_sql($sql, $params);
186 return $contextlist;
190 * Get all general data for the activity module at this context.
192 * @param \context_module $context The context to retrieve data for.
193 * @param \stdClass $user The user being written.
194 * @return \stdClass
196 protected static function get_context_module_data(\context_module $context, \stdClass $user) : \stdClass {
197 global $DB;
199 $coursecontext = $context->get_course_context();
200 $modinfo = get_fast_modinfo($coursecontext->instanceid);
201 $cm = $modinfo->cms[$context->instanceid];
202 $component = "mod_{$cm->modname}";
203 $course = $cm->get_course();
204 $moduledata = $DB->get_record($cm->modname, ['id' => $cm->instance]);
206 $basedata = (object) [
207 'name' => $cm->get_formatted_name(),
210 if (plugin_supports('mod', $cm->modname, FEATURE_MOD_INTRO, true)) {
211 $intro = $moduledata->intro;
213 $intro = writer::with_context($context)
214 ->rewrite_pluginfile_urls([], $component, 'intro', 0, $intro);
216 $options = [
217 'noclean' => true,
218 'para' => false,
219 'context' => $context,
220 'overflowdiv' => true,
222 $basedata->intro = format_text($intro, $moduledata->introformat, $options);
225 // Completion tracking.
226 $completiondata = \core_completion\privacy\provider::get_activity_completion_info($user, $course, $cm);
227 if (isset($completiondata->completionstate)) {
228 $basedata->completion = (object) [
229 'state' => $completiondata->completionstate,
233 return $basedata;
237 * Get all general data for the block at this context.
239 * @param \context_block $context The context to retrieve data for.
240 * @param \stdClass $user The user being written.
241 * @return \stdClass General data about this block instance.
243 protected static function get_context_block_data(\context_block $context, \stdClass $user) : \stdClass {
244 global $DB;
246 $block = $DB->get_record('block_instances', ['id' => $context->instanceid]);
248 $basedata = (object) [
249 'blocktype' => get_string('pluginname', 'block_' . $block->blockname)
252 return $basedata;
256 * Get all general data for the activity module at this context.
258 * @param \context_module $context The context to retrieve data for.
259 * @param \stdClass $user The user being written.
260 * @return \stdClass
262 protected static function export_context_module_files(\context_module $context, \stdClass $user) {
263 $coursecontext = $context->get_course_context();
264 $modinfo = get_fast_modinfo($coursecontext->instanceid);
265 $cm = $modinfo->cms[$context->instanceid];
266 $component = "mod_{$cm->modname}";
268 writer::with_context($context)
269 // Export the files for the intro.
270 ->export_area_files([], $component, 'intro', 0);
274 * Handle removal of 'standard' data for course modules.
276 * This will handle deletion for things such as activity completion.
278 * @param string $component The component being deleted for.
279 * @param \context $context The context to delete all data for.
281 public static function delete_data_for_all_users_in_context_course_module(string $component, \context $context) {
282 global $DB;
284 if ($context instanceof \context_module) {
285 // Delete course completion data for this context.
286 \core_completion\privacy\provider::delete_completion(null, null, $context->instanceid);
291 * Delete all 'standard' user data for the specified user in course modules.
293 * This will handle deletion for things such as activity completion.
295 * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
297 protected static function delete_data_for_user_in_course_module(approved_contextlist $contextlist) {
298 global $DB;
300 foreach ($contextlist as $context) {
301 if ($context instanceof \context_module) {
302 // Delete course completion data for this context.
303 \core_completion\privacy\provider::delete_completion($contextlist->get_user(), null, $context->instanceid);