2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Privacy provider implementation for core_contentbank.
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
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;
35 use context_coursecat;
39 * Privacy provider implementation for core_contentbank.
41 * @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
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 {
51 * Returns meta data about this system.
53 * @param collection $collection The initialised collection to add items to.
54 * @return collection A listing of user data stored through this system.
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');
70 * Export all user preferences for the contentbank
72 * @param int $userid The userid of the user whose data is to be exported.
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(
79 'core_contentbank_view_list',
81 get_string('privacy:request:preference:set', 'core_contentbank', (object) [
82 'name' => 'core_contentbank_view_list',
83 'value' => $preference,
90 * Get the list of contexts that contain user information for the specified user.
92 * @param int $userid The user to search.
93 * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
95 public static function get_contexts_for_userid(int $userid): contextlist {
96 $sql = "SELECT DISTINCT ctx.id
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)";
107 'contextlevel1' => CONTEXT_SYSTEM,
108 'contextlevel2' => CONTEXT_COURSECAT,
109 'contextlevel3' => CONTEXT_COURSE,
112 $contextlist = new contextlist();
113 $contextlist->add_from_sql($sql, $params);
119 * Get the list of users within a specific context.
121 * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
123 public static function get_users_in_context(userlist $userlist) {
124 $context = $userlist->get_context();
126 $allowedcontextlevels = [
132 if (!in_array($context->contextlevel, $allowedcontextlevels)) {
136 $sql = "SELECT cb.usercreated as userid
137 FROM {contentbank_content} cb
138 WHERE cb.contextid = :contextid";
141 'contextid' => $context->id
144 $userlist->add_from_sql('userid', $sql, $params);
148 * Export all user data for the specified user, in the specified contexts.
150 * @param approved_contextlist $contextlist The approved contexts to export information for.
152 public static function export_user_data(approved_contextlist $contextlist) {
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;
164 if (empty($contextids)) {
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,
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);
189 $lastcontextid = null;
191 get_string('name', 'core_contentbank'),
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);
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)
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);
217 $context = \context::instance_by_id($lastcontextid);
218 writer::with_context($context)->export_data($subcontext, (object)$data);
224 * Delete all data for all users in the specified context.
226 * @param context $context The specific context to delete data for.
228 public static function delete_data_for_all_users_in_context(\context $context) {
231 if (!$context instanceof context_system && !$context instanceof context_coursecat
232 && !$context instanceof context_course) {
236 static::delete_data($context, []);
240 * Delete multiple users within a single context.
242 * @param approved_userlist $userlist The approved context and user information to delete information for.
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) {
252 static::delete_data($context, $userlist->get_userids());
256 * Delete all user data for the specified user, in the specified contexts.
258 * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
260 public static function delete_data_for_user(approved_contextlist $contextlist) {
261 if (empty($contextlist->count())) {
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) {
271 static::delete_data($context, [$userid]);
276 * Delete data related to a context and users (if defined).
278 * @param context $context A context.
279 * @param array $userids The user IDs.
281 protected static function delete_data(\context $context, array $userids) {
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;
293 $fs = get_file_storage();
294 $contents = $DB->get_records_select('contentbank_content',
296 foreach ($contents as $content) {
297 $fs->delete_area_files($content->contextid, 'contentbank', 'public', $content->id);
300 // Delete all the contents.
301 $DB->delete_records_select('contentbank_content', $select, $params);