MDL-63701 editor_atto: Add support for removal of context users
[moodle.git] / lib / editor / atto / 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 Subsystem implementation for editor_atto.
19  *
20  * @package    editor_atto
21  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace editor_atto\privacy;
27 defined('MOODLE_INTERNAL') || die();
29 use \core_privacy\local\request\approved_contextlist;
30 use \core_privacy\local\request\writer;
31 use \core_privacy\local\request\helper;
32 use \core_privacy\local\request\deletion_criteria;
33 use \core_privacy\local\metadata\collection;
34 use \core_privacy\local\request\userlist;
35 use \core_privacy\local\request\approved_userlist;
37 /**
38  * Privacy Subsystem implementation for editor_atto.
39  *
40  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
41  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42  */
43 class provider implements
44         // The Atto editor stores user provided data.
45         \core_privacy\local\metadata\provider,
46         // The Atto editor provides data directly to core.
47         \core_privacy\local\request\plugin\provider,
48         // The Atto editor is capable of determining which users have data within it.
49         \core_privacy\local\request\core_userlist_provider {
51     /**
52      * Returns information about how editor_atto stores its data.
53      *
54      * @param   collection     $collection The initialised collection to add items to.
55      * @return  collection     A listing of user data stored through this system.
56      */
57     public static function get_metadata(collection $collection) : collection {
58         // There isn't much point giving details about the pageid, etc.
59         $collection->add_database_table('editor_atto_autosave', [
60                 'userid' => 'privacy:metadata:database:atto_autosave:userid',
61                 'drafttext' => 'privacy:metadata:database:atto_autosave:drafttext',
62                 'timemodified' => 'privacy:metadata:database:atto_autosave:timemodified',
63             ], 'privacy:metadata:database:atto_autosave');
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) : \core_privacy\local\request\contextlist {
75         // This block doesn't know who information is stored against unless it
76         // is at the user context.
77         $contextlist = new \core_privacy\local\request\contextlist();
78         $contextuser = \context_user::instance($userid);
80         $sql = "SELECT contextid FROM {editor_atto_autosave} WHERE userid = :userid OR contextid = :contextid";
81         $params = [
82             'userid' => $userid,
83             'contextid' => $contextuser->id,
84         ];
86         $contextlist->add_from_sql($sql, $params);
88         return $contextlist;
89     }
91     /**
92      * Get the list of users within a specific context.
93      *
94      * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
95      */
96     public static function get_users_in_context(userlist $userlist) {
97         $context = $userlist->get_context();
99         $params = [
100             'contextid' => $context->id
101         ];
103         $sql = "SELECT userid
104                   FROM {editor_atto_autosave}
105                  WHERE contextid = :contextid";
107         $userlist->add_from_sql('userid', $sql, $params);
108     }
110     /**
111      * Export all user data for the specified user, in the specified contexts.
112      *
113      * @param   approved_contextlist    $contextlist    The approved contexts to export information for.
114      */
115     public static function export_user_data(approved_contextlist $contextlist) {
116         global $DB;
118         $user = $contextlist->get_user();
120         list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
121         $contextparams['userid'] = $contextlist->get_user()->id;
123         $sql = "SELECT *
124                   FROM {editor_atto_autosave}
125                  WHERE
126                     (userid = :userid AND contextid {$contextsql})
127                     OR
128                     (contextid = :usercontext)";
130         $usercontext = \context_user::instance($user->id);
131         $contextparams['usercontext'] = $usercontext->id;
132         $autosaves = $DB->get_recordset_sql($sql, $contextparams);
134         foreach ($autosaves as $autosave) {
135             $context = \context::instance_by_id($autosave->contextid);
136             $subcontext = [
137                 get_string('autosaves', 'editor_atto'),
138                 $autosave->id,
139             ];
141             $html = writer::with_context($context)
142                 ->rewrite_pluginfile_urls($subcontext, 'user', 'draft', $autosave->draftid, $autosave->drafttext);
144             $data = (object) [
145                 'drafttext' => format_text($html, FORMAT_HTML, static::get_filter_options()),
146                 'timemodified' => \core_privacy\local\request\transform::datetime($autosave->timemodified),
147             ];
149             if ($autosave->userid != $user->id) {
150                 $data->author = \core_privacy\local\request\transform::user($autosave->userid);
151             }
153             writer::with_context($context)
154                 ->export_data($subcontext, $data)
155                 ->export_area_files($subcontext, 'user', 'draft', $autosave->draftid);
156         }
157         $autosaves->close();
158     }
160     /**
161      * Delete all data for all users in the specified context.
162      *
163      * @param   context                 $context   The specific context to delete data for.
164      */
165     public static function delete_data_for_all_users_in_context(\context $context) {
166         global $DB;
168         $DB->delete_records('editor_atto_autosave', [
169                 'contextid' => $context->id,
170             ]);
171     }
173     /**
174      * Delete multiple users within a single context.
175      *
176      * @param approved_userlist $userlist The approved context and user information to delete information for.
177      */
178     public static function delete_data_for_users(approved_userlist $userlist) {
179         global $DB;
181         $context = $userlist->get_context();
182         $userids = $userlist->get_userids();
184         list($useridsql, $useridsqlparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
185         $params = ['contextid' => $context->id] + $useridsqlparams;
187         $DB->delete_records_select('editor_atto_autosave', "contextid = :contextid AND userid {$useridsql}",
188             $params);
189     }
191     /**
192      * Delete all user data for the specified user, in the specified contexts.
193      *
194      * @param   approved_contextlist    $contextlist    The approved contexts and user information to delete information for.
195      */
196     public static function delete_data_for_user(approved_contextlist $contextlist) {
197         global $DB;
199         $user = $contextlist->get_user();
201         list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
202         $contextparams['userid'] = $user->id;
204         $sql = "SELECT * FROM {editor_atto_autosave} WHERE contextid {$contextsql}";
205         $autosaves = $DB->delete_records_select('editor_atto_autosave', "userid = :userid AND contextid {$contextsql}",
206                 $contextparams);
207     }
209     /**
210      * Get the filter options.
211      *
212      * This is shared to allow unit testing too.
213      *
214      * @return  \stdClass
215      */
216     public static function get_filter_options() {
217         return (object) [
218             'overflowdiv' => true,
219             'noclean' => true,
220         ];
221     }