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_role.
18
+ *
19
+ * @package core_role
20
+ * @copyright 2018 Carlos Escobedo <carlos@moodle.com>
21
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
+ */
23
+ namespace core_role \privacy ;
24
+ defined ('MOODLE_INTERNAL ' ) || die ();
25
+
26
+ use \core_privacy \local \metadata \collection ;
27
+ use \core_privacy \local \request \contextlist ;
28
+ use \core_privacy \local \request \approved_contextlist ;
29
+ use \core_privacy \local \request \transform ;
30
+ use \core_privacy \local \request \writer ;
31
+
32
+ /**
33
+ * Privacy provider for core_role.
34
+ *
35
+ * @copyright 2018 Carlos Escobedo <carlos@moodle.com>
36
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
+ */
38
+ class provider implements
39
+ \core_privacy \local \metadata \provider,
40
+ \core_privacy \local \request \subsystem \provider,
41
+ \core_privacy \local \request \subsystem \plugin_provider,
42
+ \core_privacy \local \request \user_preference_provider {
43
+
44
+ /**
45
+ * Get information about the user data stored by this plugin.
46
+ *
47
+ * @param collection $collection An object for storing metadata.
48
+ * @return collection The metadata.
49
+ */
50
+ public static function get_metadata (collection $ collection ) : collection {
51
+ $ rolecapabilities = [
52
+ 'roleid ' => 'privacy:metadata:role_capabilities:roleid ' ,
53
+ 'capability ' => 'privacy:metadata:role_capabilities:capability ' ,
54
+ 'permission ' => 'privacy:metadata:role_capabilities:permission ' ,
55
+ 'timemodified ' => 'privacy:metadata:role_capabilities:timemodified ' ,
56
+ 'modifierid ' => 'privacy:metadata:role_capabilities:modifierid '
57
+ ];
58
+ $ roleassignments = [
59
+ 'roleid ' => 'privacy:metadata:role_assignments:roleid ' ,
60
+ 'userid ' => 'privacy:metadata:role_assignments:userid ' ,
61
+ 'timemodified ' => 'privacy:metadata:role_assignments:timemodified ' ,
62
+ 'modifierid ' => 'privacy:metadata:role_assignments:modifierid ' ,
63
+ 'component ' => 'privacy:metadata:role_assignments:component ' ,
64
+ 'itemid ' => 'privacy:metadata:role_assignments:itemid '
65
+ ];
66
+ $ collection ->add_database_table ('role_capabilities ' , $ rolecapabilities ,
67
+ 'privacy:metadata:role_capabilities:tableexplanation ' );
68
+ $ collection ->add_database_table ('role_assignments ' , $ roleassignments ,
69
+ 'privacy:metadata:role_assignments:tableexplanation ' );
70
+
71
+ $ collection ->add_user_preference ('definerole_showadvanced ' ,
72
+ 'privacy:metadata:preference:showadvanced ' );
73
+
74
+ return $ collection ;
75
+ }
76
+ /**
77
+ * Export all user preferences for the plugin.
78
+ *
79
+ * @param int $userid The userid of the user whose data is to be exported.
80
+ */
81
+ public static function export_user_preferences (int $ userid ) {
82
+ $ showadvanced = get_user_preferences ('definerole_showadvanced ' , null , $ userid );
83
+ if ($ showadvanced !== null ) {
84
+ writer::export_user_preference ('core_role ' ,
85
+ 'definerole_showadvanced ' ,
86
+ transform::yesno ($ showadvanced ),
87
+ get_string ('privacy:metadata:preference:showadvanced ' , 'core_role ' )
88
+ );
89
+ }
90
+ }
91
+ /**
92
+ * Return all contexts for this userid.
93
+ *
94
+ * @param int $userid The user ID.
95
+ * @return contextlist The list of context IDs.
96
+ */
97
+ public static function get_contexts_for_userid (int $ userid ) : contextlist {
98
+ global $ DB ;
99
+
100
+ $ contextlist = new contextlist ();
101
+
102
+ // The role_capabilities table contains user data.
103
+ $ contexts = [
104
+ CONTEXT_SYSTEM ,
105
+ CONTEXT_USER ,
106
+ CONTEXT_COURSECAT ,
107
+ CONTEXT_COURSE ,
108
+ CONTEXT_MODULE ,
109
+ CONTEXT_BLOCK
110
+ ];
111
+ list ($ insql , $ inparams ) = $ DB ->get_in_or_equal ($ contexts , SQL_PARAMS_NAMED );
112
+ $ sql = "SELECT ctx.id
113
+ FROM {context} ctx
114
+ JOIN {role_capabilities} rc
115
+ ON rc.contextid = ctx.id
116
+ AND ((ctx.contextlevel {$ insql } AND rc.modifierid = :modifierid)
117
+ OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid)) " ;
118
+ $ params = [
119
+ 'modifierid ' => $ userid ,
120
+ 'contextlevel ' => CONTEXT_USER ,
121
+ 'userid ' => $ userid
122
+ ];
123
+ $ params += $ inparams ;
124
+
125
+ $ contextlist ->add_from_sql ($ sql , $ params );
126
+
127
+ // The role_assignments table contains user data.
128
+ $ contexts = [
129
+ CONTEXT_SYSTEM ,
130
+ CONTEXT_USER ,
131
+ CONTEXT_COURSECAT ,
132
+ CONTEXT_COURSE ,
133
+ CONTEXT_MODULE ,
134
+ CONTEXT_BLOCK
135
+ ];
136
+ list ($ insql , $ inparams ) = $ DB ->get_in_or_equal ($ contexts , SQL_PARAMS_NAMED );
137
+ $ params = [
138
+ 'userid ' => $ userid ,
139
+ 'modifierid ' => $ userid
140
+ ];
141
+ $ params += $ inparams ;
142
+ $ sql = "SELECT ctx.id
143
+ FROM {role_assignments} ra
144
+ JOIN {context} ctx
145
+ ON ctx.id = ra.contextid
146
+ AND ctx.contextlevel {$ insql }
147
+ WHERE (ra.userid = :userid
148
+ OR ra.modifierid = :modifierid)
149
+ AND ra.component != 'tool_cohortroles' " ;
150
+ $ contextlist ->add_from_sql ($ sql , $ params );
151
+
152
+ return $ contextlist ;
153
+ }
154
+ /**
155
+ * Export all user data for the specified user, in the specified contexts.
156
+ *
157
+ * @param approved_contextlist $contextlist The list of approved contexts for a user.
158
+ */
159
+ public static function export_user_data (approved_contextlist $ contextlist ) {
160
+ global $ DB ;
161
+
162
+ if (empty ($ contextlist )) {
163
+ return ;
164
+ }
165
+
166
+ $ rolesnames = self ::get_roles_name ();
167
+ $ userid = $ contextlist ->get_user ()->id ;
168
+ $ ctxfields = \context_helper::get_preload_record_columns_sql ('ctx ' );
169
+ list ($ insql , $ inparams ) = $ DB ->get_in_or_equal ($ contextlist ->get_contextids (), SQL_PARAMS_NAMED );
170
+
171
+ // Role Assignments export data.
172
+ $ contexts = [
173
+ CONTEXT_SYSTEM ,
174
+ CONTEXT_USER ,
175
+ CONTEXT_COURSECAT ,
176
+ CONTEXT_COURSE ,
177
+ CONTEXT_MODULE ,
178
+ CONTEXT_BLOCK
179
+ ];
180
+ list ($ inctxsql , $ ctxparams ) = $ DB ->get_in_or_equal ($ contexts , SQL_PARAMS_NAMED );
181
+ $ sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, $ ctxfields
182
+ FROM {role_assignments} ra
183
+ JOIN {context} ctx
184
+ ON ctx.id = ra.contextid
185
+ AND ctx.contextlevel {$ inctxsql }
186
+ AND (ra.userid = :userid OR ra.modifierid = :modifierid)
187
+ AND ra.component != 'tool_cohortroles'
188
+ JOIN {role} r
189
+ ON r.id = ra.roleid
190
+ WHERE ctx.id {$ insql }" ;
191
+ $ params = ['userid ' => $ userid , 'modifierid ' => $ userid ];
192
+ $ params += $ inparams ;
193
+ $ params += $ ctxparams ;
194
+ $ assignments = $ DB ->get_recordset_sql ($ sql , $ params );
195
+ foreach ($ assignments as $ assignment ) {
196
+ \context_helper::preload_from_record ($ assignment );
197
+ $ alldata [$ assignment ->contextid ][$ rolesnames [$ assignment ->roleid ]][] = (object )[
198
+ 'timemodified ' => transform::datetime ($ assignment ->timemodified ),
199
+ 'userid ' => transform::user ($ assignment ->userid ),
200
+ 'modifierid ' => transform::user ($ assignment ->modifierid )
201
+ ];
202
+ }
203
+ $ assignments ->close ();
204
+ if (!empty ($ alldata )) {
205
+ array_walk ($ alldata , function ($ roledata , $ contextid ) {
206
+ $ context = \context::instance_by_id ($ contextid );
207
+ array_walk ($ roledata , function ($ data , $ rolename ) use ($ context ) {
208
+ writer::with_context ($ context )->export_data (
209
+ [get_string ('privacy:metadata:role_assignments ' , 'core_role ' ), $ rolename ],
210
+ (object )$ data );
211
+ });
212
+ });
213
+ unset($ alldata );
214
+ }
215
+
216
+ // Role Capabilities export data.
217
+ $ strpermissions = self ::get_permissions_name ();
218
+ $ contexts = [
219
+ CONTEXT_SYSTEM ,
220
+ CONTEXT_USER ,
221
+ CONTEXT_COURSECAT ,
222
+ CONTEXT_COURSE ,
223
+ CONTEXT_MODULE ,
224
+ CONTEXT_BLOCK
225
+ ];
226
+ list ($ inctxsql , $ ctxparams ) = $ DB ->get_in_or_equal ($ contexts , SQL_PARAMS_NAMED );
227
+ $ sql = "SELECT rc.id, rc.contextid, rc.capability, rc.permission, rc.timemodified, rc.roleid, $ ctxfields
228
+ FROM {context} ctx
229
+ JOIN {role_capabilities} rc
230
+ ON rc.contextid = ctx.id
231
+ AND ((ctx.contextlevel {$ inctxsql } AND rc.modifierid = :modifierid)
232
+ OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))
233
+ WHERE ctx.id {$ insql }" ;
234
+ $ params = [
235
+ 'modifierid ' => $ userid ,
236
+ 'contextlevel ' => CONTEXT_USER ,
237
+ 'userid ' => $ userid
238
+ ];
239
+ $ params += $ inparams ;
240
+ $ params += $ ctxparams ;
241
+ $ capabilities = $ DB ->get_recordset_sql ($ sql , $ params );
242
+ foreach ($ capabilities as $ capability ) {
243
+ \context_helper::preload_from_record ($ capability );
244
+ $ alldata [$ capability ->contextid ][$ rolesnames [$ capability ->roleid ]][] = (object )[
245
+ 'timemodified ' => transform::datetime ($ capability ->timemodified ),
246
+ 'capability ' => $ capability ->capability ,
247
+ 'permission ' => $ strpermissions [$ capability ->permission ]
248
+ ];
249
+ }
250
+ $ capabilities ->close ();
251
+ if (!empty ($ alldata )) {
252
+ array_walk ($ alldata , function ($ capdata , $ contextid ) {
253
+ $ context = \context::instance_by_id ($ contextid );
254
+ array_walk ($ capdata , function ($ data , $ rolename ) use ($ context ) {
255
+ writer::with_context ($ context )->export_data (
256
+ [get_string ('privacy:metadata:role_capabilities ' , 'core_role ' ), $ rolename ],
257
+ (object )$ data );
258
+ });
259
+ });
260
+ }
261
+ }
262
+ /**
263
+ * Exports the data relating to tool_cohortroles component on role assignments by
264
+ * Assign user roles to cohort feature.
265
+ *
266
+ * @param int $userid The user ID.
267
+ */
268
+ public static function export_user_role_to_cohort (int $ userid ) {
269
+ global $ DB ;
270
+
271
+ $ rolesnames = self ::get_roles_name ();
272
+ $ sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, r.id as roleid
273
+ FROM {role_assignments} ra
274
+ JOIN {context} ctx
275
+ ON ctx.id = ra.contextid
276
+ AND ctx.contextlevel = :contextlevel
277
+ AND ra.component = 'tool_cohortroles'
278
+ JOIN {role} r
279
+ ON r.id = ra.roleid
280
+ WHERE ctx.instanceid = :instanceid
281
+ OR ra.userid = :userid " ;
282
+ $ params = ['userid ' => $ userid , 'instanceid ' => $ userid , 'contextlevel ' => CONTEXT_USER ];
283
+ $ assignments = $ DB ->get_recordset_sql ($ sql , $ params );
284
+ foreach ($ assignments as $ assignment ) {
285
+ $ alldata [$ assignment ->contextid ][$ rolesnames [$ assignment ->roleid ]][] = (object )[
286
+ 'timemodified ' => transform::datetime ($ assignment ->timemodified ),
287
+ 'userid ' => transform::user ($ assignment ->userid ),
288
+ 'modifierid ' => transform::user ($ assignment ->modifierid )
289
+ ];
290
+ }
291
+ $ assignments ->close ();
292
+ if (!empty ($ alldata )) {
293
+ array_walk ($ alldata , function ($ roledata , $ contextid ) {
294
+ $ context = \context::instance_by_id ($ contextid );
295
+ array_walk ($ roledata , function ($ data , $ rolename ) use ($ context ) {
296
+ writer::with_context ($ context )->export_related_data (
297
+ [get_string ('privacy:metadata:role_cohortroles ' , 'core_role ' ), $ rolename ], 'cohortroles ' ,
298
+ (object )$ data );
299
+ });
300
+ });
301
+ }
302
+ }
303
+ /**
304
+ * Delete all user data for this context.
305
+ *
306
+ * @param \context $context The context to delete data for.
307
+ */
308
+ public static function delete_data_for_all_users_in_context (\context $ context ) {
309
+ global $ DB ;
310
+
311
+ // Don't remove data from role_capabilities.
312
+ // Because this data affects the whole Moodle, there are override capabilities.
313
+ // Don't belong to the modifier user.
314
+
315
+ // Remove data from role_assignments.
316
+ if (empty ($ context )) {
317
+ return ;
318
+ }
319
+ $ DB ->delete_records ('role_assignments ' , ['contextid ' => $ context ->id ]);
320
+ }
321
+ /**
322
+ * Delete all user data for this user only.
323
+ *
324
+ * @param approved_contextlist $contextlist The list of approved contexts for a user.
325
+ */
326
+ public static function delete_data_for_user (approved_contextlist $ contextlist ) {
327
+ global $ DB ;
328
+
329
+ // Don't remove data from role_capabilities.
330
+ // Because this data affects the whole Moodle, there are override capabilities.
331
+ // Don't belong to the modifier user.
332
+
333
+ // Remove data from role_assignments.
334
+ if (empty ($ contextlist ->count ())) {
335
+ return ;
336
+ }
337
+ $ userid = $ contextlist ->get_user ()->id ;
338
+ foreach ($ contextlist ->get_contexts () as $ context ) {
339
+ // Only delete the roles assignments where the user is assigned in all contexts.
340
+ $ DB ->delete_records ('role_assignments ' , ['userid ' => $ userid , 'contextid ' => $ context ->id ]);
341
+ }
342
+ }
343
+ /**
344
+ * Delete user entries in role_assignments related to the feature
345
+ * Assign user roles to cohort feature.
346
+ *
347
+ * @param int $userid The user ID.
348
+ */
349
+ public static function delete_user_role_to_cohort (int $ userid ) {
350
+ global $ DB ;
351
+
352
+ // Delete entries where userid is a mentor by tool_cohortroles.
353
+ $ DB ->delete_records ('role_assignments ' , ['userid ' => $ userid , 'component ' => 'tool_cohortroles ' ]);
354
+ }
355
+ /**
356
+ * Get all the localised roles name in a simple array.
357
+ *
358
+ * @return array Array of name of the roles by roleid.
359
+ */
360
+ protected static function get_roles_name () {
361
+ $ roles = role_fix_names (get_all_roles (), \context_system::instance (), ROLENAME_ORIGINAL );
362
+ $ rolesnames = array ();
363
+ foreach ($ roles as $ role ) {
364
+ $ rolesnames [$ role ->id ] = $ role ->localname ;
365
+ }
366
+ return $ rolesnames ;
367
+ }
368
+ /**
369
+ * Get all the permissions name in a simple array.
370
+ *
371
+ * @return array Array of permissions name.
372
+ */
373
+ protected static function get_permissions_name () {
374
+ $ strpermissions = array (
375
+ CAP_INHERIT => get_string ('inherit ' , 'role ' ),
376
+ CAP_ALLOW => get_string ('allow ' , 'role ' ),
377
+ CAP_PREVENT => get_string ('prevent ' , 'role ' ),
378
+ CAP_PROHIBIT => get_string ('prohibit ' , 'role ' )
379
+ );
380
+ return $ strpermissions ;
381
+ }
382
+ }
0 commit comments