on-demand release 3.9dev+
[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 {
49     /**
50      * Returns meta data about this system.
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_database_table('contentbank_content', [
57             'name' => 'privacy:metadata:content:name',
58             'contenttype' => 'privacy:metadata:content:contenttype',
59             'usercreated' => 'privacy:metadata:content:usercreated',
60             'usermodified' => 'privacy:metadata:content:usermodified',
61             'timecreated' => 'privacy:metadata:content:timecreated',
62             'timemodified' => 'privacy:metadata:content:timemodified',
63         ], 'privacy:metadata:contentbankcontent');
65         return $collection;
66     }
68     /**
69      * Get the list of contexts that contain user information for the specified user.
70      *
71      * @param   int $userid The user to search.
72      * @return  contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
73      */
74     public static function get_contexts_for_userid(int $userid): contextlist {
75         $sql = "SELECT DISTINCT ctx.id
76                   FROM {context} ctx
77                   JOIN {contentbank_content} cb
78                        ON cb.contextid = ctx.id
79                  WHERE cb.usercreated = :userid
80                        AND (ctx.contextlevel = :contextlevel1
81                            OR ctx.contextlevel = :contextlevel2
82                            OR ctx.contextlevel = :contextlevel3)";
84         $params = [
85             'userid'        => $userid,
86             'contextlevel1' => CONTEXT_SYSTEM,
87             'contextlevel2' => CONTEXT_COURSECAT,
88             'contextlevel3' => CONTEXT_COURSE,
89         ];
91         $contextlist = new contextlist();
92         $contextlist->add_from_sql($sql, $params);
94         return $contextlist;
95     }
97     /**
98      * Get the list of users within a specific context.
99      *
100      * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
101      */
102     public static function get_users_in_context(userlist $userlist) {
103         $context = $userlist->get_context();
105         $allowedcontextlevels = [
106             CONTEXT_SYSTEM,
107             CONTEXT_COURSECAT,
108             CONTEXT_COURSE,
109         ];
111         if (!in_array($context->contextlevel, $allowedcontextlevels)) {
112             return;
113         }
115         $sql = "SELECT cb.usercreated as userid
116                   FROM {contentbank_content} cb
117                  WHERE cb.contextid = :contextid";
119         $params = [
120             'contextid' => $context->id
121         ];
123         $userlist->add_from_sql('userid', $sql, $params);
124     }
126     /**
127      * Export all user data for the specified user, in the specified contexts.
128      *
129      * @param approved_contextlist $contextlist The approved contexts to export information for.
130      */
131     public static function export_user_data(approved_contextlist $contextlist) {
132         global $DB;
134         // Remove contexts different from SYSTEM, COURSECAT or COURSE.
135         $contextids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
136             if ($context->contextlevel == CONTEXT_SYSTEM || $context->contextlevel == CONTEXT_COURSECAT
137                 || $context->contextlevel == CONTEXT_COURSE) {
138                 $carry[] = $context->id;
139             }
140             return $carry;
141         }, []);
143         if (empty($contextids)) {
144             return;
145         }
147         $userid = $contextlist->get_user()->id;
149         list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
150         // Retrieve the contentbank_content records created for the user.
151         $sql = "SELECT cb.id,
152                        cb.name,
153                        cb.contenttype,
154                        cb.usercreated,
155                        cb.usermodified,
156                        cb.timecreated,
157                        cb.timemodified,
158                        cb.contextid
159                   FROM {contentbank_content} cb
160                  WHERE cb.usercreated = :userid
161                        AND cb.contextid {$contextsql}
162                  ORDER BY cb.contextid";
164         $params = ['userid' => $userid] + $contextparams;
166         $contents = $DB->get_recordset_sql($sql, $params);
167         $data = [];
168         $lastcontextid = null;
169         $subcontext = [
170             get_string('name', 'core_contentbank'),
171         ];
172         foreach ($contents as $content) {
173             // The core_contentbank data export is organised in:
174             // {Sytem|Course Category|Course Context Level}/Content/data.json.
175             if ($lastcontextid && $lastcontextid != $content->contextid) {
176                 $context = \context::instance_by_id($lastcontextid);
177                 writer::with_context($context)->export_data($subcontext, (object)$data);
178                 $data = [];
179             }
180             $data[] = (object) [
181                 'name' => $content->name,
182                 'contenttype' => $content->contenttype,
183                 'usercreated' => transform::user($content->usercreated),
184                 'usermodified' => transform::user($content->usermodified),
185                 'timecreated' => transform::datetime($content->timecreated),
186                 'timemodified' => transform::datetime($content->timemodified)
187             ];
188             $lastcontextid = $content->contextid;
190             // The core_contentbank files export is organised in:
191             // {Sytem|Course Category|Course Context Level}/Content/_files/public/_itemid/filename.
192             $context = \context::instance_by_id($lastcontextid);
193             writer::with_context($context)->export_area_files($subcontext, 'contentbank', 'public', $content->id);
194         }
195         if (!empty($data)) {
196             $context = \context::instance_by_id($lastcontextid);
197             writer::with_context($context)->export_data($subcontext, (object)$data);
198         }
199         $contents->close();
200     }
202     /**
203      * Delete all data for all users in the specified context.
204      *
205      * @param   context $context The specific context to delete data for.
206      */
207     public static function delete_data_for_all_users_in_context(\context $context) {
208         global $DB;
210         if (!$context instanceof context_system && !$context instanceof context_coursecat
211                 && !$context instanceof context_course) {
212             return;
213         }
215         static::delete_data($context, []);
216     }
218     /**
219      * Delete multiple users within a single context.
220      *
221      * @param approved_userlist $userlist The approved context and user information to delete information for.
222      */
223     public static function delete_data_for_users(approved_userlist $userlist) {
224         $context = $userlist->get_context();
226         if (!$context instanceof context_system && !$context instanceof context_coursecat
227                 && !$context instanceof context_course) {
228             return;
229         }
231         static::delete_data($context, $userlist->get_userids());
232     }
234     /**
235      * Delete all user data for the specified user, in the specified contexts.
236      *
237      * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
238      */
239     public static function delete_data_for_user(approved_contextlist $contextlist) {
240         if (empty($contextlist->count())) {
241             return;
242         }
244         $userid = $contextlist->get_user()->id;
245         foreach ($contextlist->get_contexts() as $context) {
246             if (!$context instanceof context_system && !$context instanceof context_coursecat
247             && !$context instanceof context_course) {
248                 continue;
249             }
250             static::delete_data($context, [$userid]);
251         }
252     }
254     /**
255      * Delete data related to a context and users (if defined).
256      *
257      * @param context $context A context.
258      * @param array $userids The user IDs.
259      */
260     protected static function delete_data(\context $context, array $userids) {
261         global $DB;
263         $params = ['contextid' => $context->id];
264         $select = 'contextid = :contextid';
266         // Delete the Content Bank files.
267         if (!empty($userids)) {
268             list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
269             $params += $inparams;
270             $select .= ' AND usercreated '.$insql;
271         }
272         $fs = get_file_storage();
273         $contents = $DB->get_records_select('contentbank_content',
274             $select, $params);
275         foreach ($contents as $content) {
276             $fs->delete_area_files($content->contextid, 'contentbank', 'public', $content->id);
277         }
279         // Delete all the contents.
280         $DB->delete_records_select('contentbank_content', $select, $params);
281     }