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