cbee6444deeb3a4977239c740e4dd5e555a8d909
[moodle.git] / blocks / classes / privacy / provider.php
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/>.
17 /**
18  * Data provider.
19  *
20  * @package    core_block
21  * @copyright  2018 Frédéric Massart
22  * @author     Frédéric Massart <fred@branchup.tech>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 namespace core_block\privacy;
27 defined('MOODLE_INTERNAL') || die();
29 use context;
30 use context_block;
31 use core_privacy\local\metadata\collection;
32 use core_privacy\local\request\approved_contextlist;
33 use core_privacy\local\request\transform;
34 use core_privacy\local\request\writer;
36 /**
37  * Data provider class.
38  *
39  * @package    core_block
40  * @copyright  2018 Frédéric Massart
41  * @author     Frédéric Massart <fred@branchup.tech>
42  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43  */
44 class provider implements
45     \core_privacy\local\metadata\provider,
46     \core_privacy\local\request\subsystem\provider,
47     \core_privacy\local\request\user_preference_provider {
49     /**
50      * Returns metadata.
51      *
52      * @param collection $collection The initialised collection to add items to.
53      * @return collection A listing of user data stored through this system.
54      */
55     public static function get_metadata(collection $collection) : collection {
56         $collection->add_user_preference('blockIDhidden', 'privacy:metadata:userpref:hiddenblock');
57         $collection->add_user_preference('docked_block_instance_ID', 'privacy:metadata:userpref:dockedinstance');
58         return $collection;
59     }
61     /**
62      * Get the list of contexts that contain user information for the specified user.
63      *
64      * @param int $userid The user to search.
65      * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
66      */
67     public static function get_contexts_for_userid(int $userid) : \core_privacy\local\request\contextlist {
68         global $DB;
69         $contextlist = new \core_privacy\local\request\contextlist();
71         // Fetch the block instance IDs.
72         $likehidden = $DB->sql_like('name', ':hidden', false, false);
73         $likedocked = $DB->sql_like('name', ':docked', false, false);
74         $sql = "userid = :userid AND ($likehidden OR $likedocked)";
75         $params = [
76             'userid' => $userid,
77             'hidden' => 'block%hidden',
78             'docked' => 'docked_block_instance_%',
79         ];
80         $prefs = $DB->get_fieldset_select('user_preferences', 'name', $sql, $params);
82         $instanceids = array_unique(array_map(function($prefname) {
83             if (preg_match('/^block(\d+)hidden$/', $prefname, $matches)) {
84                 return $matches[1];
85             } else if (preg_match('/^docked_block_instance_(\d+)$/', $prefname, $matches)) {
86                 return $matches[1];
87             }
88             return 0;
89         }, $prefs));
91         // Find the context of the instances.
92         if (!empty($instanceids)) {
93             list($insql, $inparams) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
94             $sql = "
95                 SELECT ctx.id
96                   FROM {context} ctx
97                  WHERE ctx.instanceid $insql
98                    AND ctx.contextlevel = :blocklevel";
99             $params = array_merge($inparams, ['blocklevel' => CONTEXT_BLOCK]);
100             $contextlist->add_from_sql($sql, $params);
101         }
103         return $contextlist;
104     }
106     /**
107      * Export all user data for the specified user, in the specified contexts.
108      *
109      * @param approved_contextlist $contextlist The approved contexts to export information for.
110      */
111     public static function export_user_data(approved_contextlist $contextlist) {
112         global $DB;
113         $userid = $contextlist->get_user()->id;
115         // Extract the block instance IDs.
116         $instanceids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
117             if ($context->contextlevel == CONTEXT_BLOCK) {
118                 $carry[] = $context->instanceid;
119             }
120             return $carry;
121         }, []);
122         if (empty($instanceids)) {
123             return;
124         }
126         // Query the blocks and their preferences.
127         list($insql, $inparams) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
128         $hiddenkey = $DB->sql_concat("'block'", 'bi.id', "'hidden'");
129         $dockedkey = $DB->sql_concat("'docked_block_instance_'", 'bi.id');
130         $sql = "
131             SELECT bi.id, h.value AS prefhidden, d.value AS prefdocked
132               FROM {block_instances} bi
133          LEFT JOIN {user_preferences} h
134                 ON h.userid = :userid1
135                AND h.name = $hiddenkey
136          LEFT JOIN {user_preferences} d
137                 ON d.userid = :userid2
138                AND d.name = $dockedkey
139              WHERE bi.id $insql
140                AND (h.id IS NOT NULL
141                 OR d.id IS NOT NULL)";
142         $params = array_merge($inparams, [
143             'userid1' => $userid,
144             'userid2' => $userid,
145         ]);
147         // Export all the things.
148         $dockedstr = get_string('privacy:request:blockisdocked', 'core_block');
149         $hiddenstr = get_string('privacy:request:blockishidden', 'core_block');
150         $recordset = $DB->get_recordset_sql($sql, $params);
151         foreach ($recordset as $record) {
152             $context = context_block::instance($record->id);
153             if ($record->prefdocked !== null) {
154                 writer::with_context($context)->export_user_preference(
155                     'core_block',
156                     'block_is_docked',
157                     transform::yesno($record->prefdocked),
158                     $dockedstr
159                 );
160             }
161             if ($record->prefhidden !== null) {
162                 writer::with_context($context)->export_user_preference(
163                     'core_block',
164                     'block_is_hidden',
165                     transform::yesno($record->prefhidden),
166                     $hiddenstr
167                 );
168             }
169         }
170         $recordset->close();
171     }
173     /**
174      * Export all user preferences for the plugin.
175      *
176      * @param int $userid The userid of the user whose data is to be exported.
177      */
178     public static function export_user_preferences(int $userid) {
179       // Our preferences aren't site-wide so they are exported in export_user_data.
180     }
182     /**
183      * Delete all data for all users in the specified context.
184      *
185      * @param context $context The specific context to delete data for.
186      */
187     public static function delete_data_for_all_users_in_context(context $context) {
188         global $DB;
189         if ($context->contextlevel != CONTEXT_BLOCK) {
190             return;
191         }
193         // Delete the user preferences.
194         $instanceid = $context->instanceid;
195         $DB->delete_records_list('user_preferences', 'name', [
196             "block{$instanceid}hidden",
197             "docked_block_instance_{$instanceid}"
198         ]);
199     }
201     /**
202      * Delete all user data for the specified user, in the specified contexts.
203      *
204      * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
205      */
206     public static function delete_data_for_user(approved_contextlist $contextlist) {
207         global $DB;
208         $userid = $contextlist->get_user()->id;
209         $prefnames = array_reduce($contextlist->get_contexts(), function($carry, $context) {
210             if ($context->contextlevel == CONTEXT_BLOCK) {
211                 $carry[] = "block{$context->instanceid}hidden";
212                 $carry[] = "docked_block_instance_{$context->instanceid}";
213             }
214             return $carry;
215         }, []);
217         if (empty($prefnames)) {
218             return;
219         }
221         list($insql, $inparams) = $DB->get_in_or_equal($prefnames, SQL_PARAMS_NAMED);
222         $sql = "userid = :userid AND name $insql";
223         $params = array_merge($inparams, ['userid' => $userid]);
224         $DB->delete_records_select('user_preferences', $sql, $params);
225     }