MDL-68796 core_contentbank: Store view preferences
[moodle.git] / contentbank / 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  * Privacy provider implementation for core_contentbank.
19  *
20  * @package    core_contentbank
21  * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace core_contentbank\privacy;
27 use core_privacy\local\metadata\collection;
28 use core_privacy\local\request\approved_contextlist;
29 use core_privacy\local\request\contextlist;
30 use core_privacy\local\request\transform;
31 use core_privacy\local\request\writer;
32 use core_privacy\local\request\userlist;
33 use core_privacy\local\request\approved_userlist;
34 use context_system;
35 use context_coursecat;
36 use context_course;
38 /**
39  * Privacy provider implementation for core_contentbank.
40  *
41  * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
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\core_userlist_provider,
47     \core_privacy\local\request\plugin\provider,
48     \core_privacy\local\request\user_preference_provider {
50     /**
51      * Returns meta data about this system.
52      *
53      * @param collection $collection The initialised collection to add items to.
54      * @return collection A listing of user data stored through this system.
55      */
56     public static function get_metadata(collection $collection): collection {
57         $collection->add_database_table('contentbank_content', [
58             'name' => 'privacy:metadata:content:name',
59             'contenttype' => 'privacy:metadata:content:contenttype',
60             'usercreated' => 'privacy:metadata:content:usercreated',
61             'usermodified' => 'privacy:metadata:content:usermodified',
62             'timecreated' => 'privacy:metadata:content:timecreated',
63             'timemodified' => 'privacy:metadata:content:timemodified',
64         ], 'privacy:metadata:contentbankcontent');
66         return $collection;
67     }
69     /**
70      * Export all user preferences for the contentbank
71      *
72      * @param int $userid The userid of the user whose data is to be exported.
73      */
74     public static function export_user_preferences(int $userid) {
75         $preference = get_user_preferences('core_contentbank_view_list', null, $userid);
76         if (isset($preference)) {
77             writer::export_user_preference(
78                     'core_contentbank',
79                     'core_contentbank_view_list',
80                     $preference,
81                     get_string('privacy:request:preference:set', 'core_contentbank', (object) [
82                             'name' => 'core_contentbank_view_list',
83                             'value' => $preference,
84                     ])
85             );
86         }
87     }
89     /**
90      * Get the list of contexts that contain user information for the specified user.
91      *
92      * @param   int $userid The user to search.
93      * @return  contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
94      */
95     public static function get_contexts_for_userid(int $userid): contextlist {
96         $sql = "SELECT DISTINCT ctx.id
97                   FROM {context} ctx
98                   JOIN {contentbank_content} cb
99                        ON cb.contextid = ctx.id
100                  WHERE cb.usercreated = :userid
101                        AND (ctx.contextlevel = :contextlevel1
102                            OR ctx.contextlevel = :contextlevel2
103                            OR ctx.contextlevel = :contextlevel3)";
105         $params = [
106             'userid'        => $userid,
107             'contextlevel1' => CONTEXT_SYSTEM,
108             'contextlevel2' => CONTEXT_COURSECAT,
109             'contextlevel3' => CONTEXT_COURSE,
110         ];
112         $contextlist = new contextlist();
113         $contextlist->add_from_sql($sql, $params);
115         return $contextlist;
116     }
118     /**
119      * Get the list of users within a specific context.
120      *
121      * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
122      */
123     public static function get_users_in_context(userlist $userlist) {
124         $context = $userlist->get_context();
126         $allowedcontextlevels = [
127             CONTEXT_SYSTEM,
128             CONTEXT_COURSECAT,
129             CONTEXT_COURSE,
130         ];
132         if (!in_array($context->contextlevel, $allowedcontextlevels)) {
133             return;
134         }
136         $sql = "SELECT cb.usercreated as userid
137                   FROM {contentbank_content} cb
138                  WHERE cb.contextid = :contextid";
140         $params = [
141             'contextid' => $context->id
142         ];
144         $userlist->add_from_sql('userid', $sql, $params);
145     }
147     /**
148      * Export all user data for the specified user, in the specified contexts.
149      *
150      * @param approved_contextlist $contextlist The approved contexts to export information for.
151      */
152     public static function export_user_data(approved_contextlist $contextlist) {
153         global $DB;
155         // Remove contexts different from SYSTEM, COURSECAT or COURSE.
156         $contextids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
157             if ($context->contextlevel == CONTEXT_SYSTEM || $context->contextlevel == CONTEXT_COURSECAT
158                 || $context->contextlevel == CONTEXT_COURSE) {
159                 $carry[] = $context->id;
160             }
161             return $carry;
162         }, []);
164         if (empty($contextids)) {
165             return;
166         }
168         $userid = $contextlist->get_user()->id;
170         list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
171         // Retrieve the contentbank_content records created for the user.
172         $sql = "SELECT cb.id,
173                        cb.name,
174                        cb.contenttype,
175                        cb.usercreated,
176                        cb.usermodified,
177                        cb.timecreated,
178                        cb.timemodified,
179                        cb.contextid
180                   FROM {contentbank_content} cb
181                  WHERE cb.usercreated = :userid
182                        AND cb.contextid {$contextsql}
183                  ORDER BY cb.contextid";
185         $params = ['userid' => $userid] + $contextparams;
187         $contents = $DB->get_recordset_sql($sql, $params);
188         $data = [];
189         $lastcontextid = null;
190         $subcontext = [
191             get_string('name', 'core_contentbank'),
192         ];
193         foreach ($contents as $content) {
194             // The core_contentbank data export is organised in:
195             // {Sytem|Course Category|Course Context Level}/Content/data.json.
196             if ($lastcontextid && $lastcontextid != $content->contextid) {
197                 $context = \context::instance_by_id($lastcontextid);
198                 writer::with_context($context)->export_data($subcontext, (object)$data);
199                 $data = [];
200             }
201             $data[] = (object) [
202                 'name' => $content->name,
203                 'contenttype' => $content->contenttype,
204                 'usercreated' => transform::user($content->usercreated),
205                 'usermodified' => transform::user($content->usermodified),
206                 'timecreated' => transform::datetime($content->timecreated),
207                 'timemodified' => transform::datetime($content->timemodified)
208             ];
209             $lastcontextid = $content->contextid;
211             // The core_contentbank files export is organised in:
212             // {Sytem|Course Category|Course Context Level}/Content/_files/public/_itemid/filename.
213             $context = \context::instance_by_id($lastcontextid);
214             writer::with_context($context)->export_area_files($subcontext, 'contentbank', 'public', $content->id);
215         }
216         if (!empty($data)) {
217             $context = \context::instance_by_id($lastcontextid);
218             writer::with_context($context)->export_data($subcontext, (object)$data);
219         }
220         $contents->close();
221     }
223     /**
224      * Delete all data for all users in the specified context.
225      *
226      * @param   context $context The specific context to delete data for.
227      */
228     public static function delete_data_for_all_users_in_context(\context $context) {
229         global $DB;
231         if (!$context instanceof context_system && !$context instanceof context_coursecat
232                 && !$context instanceof context_course) {
233             return;
234         }
236         static::delete_data($context, []);
237     }
239     /**
240      * Delete multiple users within a single context.
241      *
242      * @param approved_userlist $userlist The approved context and user information to delete information for.
243      */
244     public static function delete_data_for_users(approved_userlist $userlist) {
245         $context = $userlist->get_context();
247         if (!$context instanceof context_system && !$context instanceof context_coursecat
248                 && !$context instanceof context_course) {
249             return;
250         }
252         static::delete_data($context, $userlist->get_userids());
253     }
255     /**
256      * Delete all user data for the specified user, in the specified contexts.
257      *
258      * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
259      */
260     public static function delete_data_for_user(approved_contextlist $contextlist) {
261         if (empty($contextlist->count())) {
262             return;
263         }
265         $userid = $contextlist->get_user()->id;
266         foreach ($contextlist->get_contexts() as $context) {
267             if (!$context instanceof context_system && !$context instanceof context_coursecat
268             && !$context instanceof context_course) {
269                 continue;
270             }
271             static::delete_data($context, [$userid]);
272         }
273     }
275     /**
276      * Delete data related to a context and users (if defined).
277      *
278      * @param context $context A context.
279      * @param array $userids The user IDs.
280      */
281     protected static function delete_data(\context $context, array $userids) {
282         global $DB;
284         $params = ['contextid' => $context->id];
285         $select = 'contextid = :contextid';
287         // Delete the Content Bank files.
288         if (!empty($userids)) {
289             list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
290             $params += $inparams;
291             $select .= ' AND usercreated '.$insql;
292         }
293         $fs = get_file_storage();
294         $contents = $DB->get_records_select('contentbank_content',
295             $select, $params);
296         foreach ($contents as $content) {
297             $fs->delete_area_files($content->contextid, 'contentbank', 'public', $content->id);
298         }
300         // Delete all the contents.
301         $DB->delete_records_select('contentbank_content', $select, $params);
302     }