MDL-62426 core_enrol: control enrolment subcontexts at the provider
[moodle.git] / enrol / classes / privacy / provider.php
CommitLineData
451f4a28 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 * Privacy Subsystem implementation for core_enrol.
18 *
19 * @package core_enrol
20 * @copyright 2018 Carlos Escobedo <carlos@moodle.com>
21 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 */
23namespace core_enrol\privacy;
24defined('MOODLE_INTERNAL') || die();
25
26use core_privacy\local\metadata\collection;
27use core_privacy\local\request\approved_contextlist;
28use core_privacy\local\request\context;
29use core_privacy\local\request\contextlist;
30use core_privacy\local\request\transform;
31use core_privacy\local\request\writer;
32
33/**
34 * Privacy Subsystem for core_enrol implementing metadata and plugin providers.
35 *
36 * @copyright 2018 Carlos Escobedo <carlos@moodle.com>
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 */
39class provider implements
40 \core_privacy\local\metadata\provider,
41 \core_privacy\local\request\subsystem\provider {
42 /**
43 * Returns meta data about this system.
44 *
45 * @param collection $collection The initialised collection to add items to.
46 * @return collection A listing of user data stored through this system.
47 */
48 public static function get_metadata(collection $collection) : collection {
49 $collection->add_database_table(
50 'user_enrolments',
51 [
52 'status' => 'privacy:metadata:user_enrolments:status',
53 'enrolid' => 'privacy:metadata:user_enrolments:enrolid',
54 'userid' => 'privacy:metadata:user_enrolments:userid',
55 'timestart' => 'privacy:metadata:user_enrolments:timestart',
56 'timeend' => 'privacy:metadata:user_enrolments:timeend',
57 'modifierid' => 'privacy:metadata:user_enrolments:modifierid',
58 'timecreated' => 'privacy:metadata:user_enrolments:timecreated',
59 'timemodified' => 'privacy:metadata:user_enrolments:timemodified'
60 ],
61 'privacy:metadata:user_enrolments:tableexplanation'
62 );
63
64 return $collection;
65 }
66 /**
67 * Get the list of contexts that contain user information for the specified user.
68 *
69 * @param int $userid The user to search.
70 * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
71 */
72 public static function get_contexts_for_userid(int $userid) : contextlist {
73 $sql = "SELECT ctx.id
74 FROM {user_enrolments} ue
75 JOIN {enrol} e
76 ON e.id = ue.enrolid
77 AND ue.userid = :userid
78 JOIN {context} ctx
79 ON ctx.instanceid = e.courseid
80 AND ctx.contextlevel = :contextlevel";
81 $params = [
82 'contextlevel' => CONTEXT_COURSE,
83 'userid' => $userid
84 ];
85 $contextlist = new contextlist();
86 $contextlist->add_from_sql($sql, $params);
87
88 return $contextlist;
89 }
90 /**
91 * Export all user data for the specified user, in the specified contexts.
92 *
93 * @param approved_contextlist $contextlist The approved contexts to export information for.
94 */
95 public static function export_user_data(approved_contextlist $contextlist) {
96 global $DB;
97
98 if (empty($contextlist->count())) {
99 return;
100 }
101 $userid = $contextlist->get_user()->id;
102 list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
103 $params = [
104 'contextlevel' => CONTEXT_COURSE,
105 'userid' => $userid
106 ];
107 $params += $inparams;
108 $sql = "SELECT ue.id,
109 ue.status,
110 ue.timestart,
111 ue.timeend,
112 ue.timecreated,
113 ue.timemodified,
114 e.enrol,
115 ctx.id as contextid
116 FROM {user_enrolments} ue
117 JOIN {enrol} e
118 ON e.id = ue.enrolid
119 AND ue.userid = :userid
120 JOIN {context} ctx
121 ON ctx.instanceid = e.courseid
122 AND ctx.contextlevel = :contextlevel
123 WHERE ctx.id $insql
124 ORDER BY ctx.id, e.enrol";
125 $data = [];
126 $lastcontextid = null;
127 $lastenrol = null;
128 $path = [get_string('privacy:metadata:user_enrolments', 'core_enrol')];
129 $flush = function($lastcontextid, $lastenrol, $data) use ($path) {
130 $context = \context::instance_by_id($lastcontextid);
131 writer::with_context($context)->export_related_data(
132 $path,
133 $lastenrol,
134 (object)$data
135 );
136 };
137 $userenrolments = $DB->get_recordset_sql($sql, $params);
138 foreach ($userenrolments as $userenrolment) {
139 if (($lastcontextid && $lastcontextid != $userenrolment->contextid) ||
140 ($lastenrol && $lastenrol != $userenrolment->enrol)) {
141 $flush($lastcontextid, $lastenrol, $data);
142 $data = [];
143 }
144 $data[] = (object) [
145 'status' => $userenrolment->status,
146 'timecreated' => transform::datetime($userenrolment->timecreated),
147 'timemodified' => transform::datetime($userenrolment->timemodified),
148 'timestart' => transform::datetime($userenrolment->timestart),
149 'timeend' => transform::datetime($userenrolment->timeend)
150 ];
151 $lastcontextid = $userenrolment->contextid;
152 $lastenrol = $userenrolment->enrol;
153 }
154 if (!empty($data)) {
155 $flush($lastcontextid, $lastenrol, $data);
156 }
157 $userenrolments->close();
158 }
159 /**
160 * Delete all data for all users in the specified context.
161 *
162 * @param context $context The specific context to delete data for.
163 */
164 public static function delete_data_for_all_users_in_context(\context $context) {
165 global $DB;
166
167 if (empty($context)) {
168 return;
169 }
170 // Sanity check that context is at the User context level.
171 if ($context->contextlevel == CONTEXT_COURSE) {
172 $sql = "SELECT ue.id
173 FROM {user_enrolments} ue
174 JOIN {enrol} e
175 ON e.id = ue.enrolid
176 JOIN {context} ctx
177 ON ctx.instanceid = e.courseid
178 WHERE ctx.id = :contextid";
179 $params = ['contextid' => $context->id];
180 $enrolsids = $DB->get_fieldset_sql($sql, $params);
181 if (!empty($enrolsids)) {
182 list($insql, $inparams) = $DB->get_in_or_equal($enrolsids, SQL_PARAMS_NAMED);
183 static::delete_user_data($insql, $inparams);
184 }
185 }
186 }
187 /**
188 * Delete all user data for the specified user, in the specified contexts.
189 *
190 * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
191 */
192 public static function delete_data_for_user(approved_contextlist $contextlist) {
193 global $DB;
194
195 if (empty($contextlist->count())) {
196 return;
197 }
198 $userid = $contextlist->get_user()->id;
199 list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
200 $params = [
201 'contextlevel' => CONTEXT_COURSE,
202 'userid' => $userid
203 ];
204 $params += $inparams;
205 $sql = "SELECT ue.id
206 FROM {user_enrolments} ue
207 JOIN {enrol} e
208 ON e.id = ue.enrolid
209 AND ue.userid = :userid
210 JOIN {context} ctx
211 ON ctx.instanceid = e.courseid
212 AND ctx.contextlevel = :contextlevel
213 WHERE ctx.id $insql";
214 $enrolsids = $DB->get_fieldset_sql($sql, $params);
215 if (!empty($enrolsids)) {
216 list($insql, $inparams) = $DB->get_in_or_equal($enrolsids, SQL_PARAMS_NAMED);
217 static::delete_user_data($insql, $inparams);
218 }
219 }
220
221 /**
222 * Delete data from $tablename with the IDs returned by $sql query.
223 *
224 * @param string $sql SQL query for getting the IDs of the uer enrolments entries to delete.
225 * @param array $params SQL params for the query.
226 */
227 protected static function delete_user_data(string $sql, array $params) {
228 global $DB;
229
230 $DB->delete_records_select('user_enrolments', "id $sql", $params);
231 }
232
72580c08
JD
233 /**
234 * Get the subcontext for export.
235 *
236 * @param array $subcontext Any additional subcontext to use.
237 * @return array The array containing the full subcontext, i.e. [enrolments, subcontext]
238 */
239 public static function get_subcontext(array $subcontext) {
240 return array_merge(
241 [get_string('privacy:metadata:user_enrolments', 'core_enrol')],
242 $subcontext
243 );
244 }
451f4a28 245}