67e4e515e5d52684b11b728f3ce5602d0e262c4e
[moodle.git] / admin / tool / policy / 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 tool_policy.
19  *
20  * @package    tool_policy
21  * @copyright  2018 Sara Arjona <sara@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace tool_policy\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\moodle_content_writer;
31 use core_privacy\local\request\transform;
32 use core_privacy\local\request\writer;
34 defined('MOODLE_INTERNAL') || die();
36 /**
37  * Implementation of the privacy subsystem plugin provider for the policy tool.
38  *
39  * @copyright  2018 Sara Arjona <sara@moodle.com>
40  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41  */
42 class provider implements
43         // This tool stores user data.
44         \core_privacy\local\metadata\provider,
46         // This tool may provide access to and deletion of user data.
47         \core_privacy\local\request\plugin\provider {
49     /**
50      * Return the fields which contain personal data.
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(
57             'tool_policy_acceptances',
58             [
59                 'policyversionid' => 'privacy:metadata:acceptances:policyversionid',
60                 'userid' => 'privacy:metadata:acceptances:userid',
61                 'status' => 'privacy:metadata:acceptances:status',
62                 'lang' => 'privacy:metadata:acceptances:lang',
63                 'usermodified' => 'privacy:metadata:acceptances:usermodified',
64                 'timecreated' => 'privacy:metadata:acceptances:timecreated',
65                 'timemodified' => 'privacy:metadata:acceptances:timemodified',
66                 'note' => 'privacy:metadata:acceptances:note',
67             ],
68             'privacy:metadata:acceptances'
69         );
71         $collection->add_database_table(
72             'tool_policy_versions',
73             [
74                 'name' => 'privacy:metadata:versions:name',
75                 'type' => 'privacy:metadata:versions:type',
76                 'audience' => 'privacy:metadata:versions:audience',
77                 'archived' => 'privacy:metadata:versions:archived',
78                 'usermodified' => 'privacy:metadata:versions:usermodified',
79                 'timecreated' => 'privacy:metadata:versions:timecreated',
80                 'timemodified' => 'privacy:metadata:versions:timemodified',
81                 'policyid' => 'privacy:metadata:versions:policyid',
82                 'revision' => 'privacy:metadata:versions:revision',
83                 'summary' => 'privacy:metadata:versions:summary',
84                 'summaryformat' => 'privacy:metadata:versions:summaryformat',
85                 'content' => 'privacy:metadata:versions:content',
86                 'contentformat' => 'privacy:metadata:versions:contentformat',
87             ],
88             'privacy:metadata:versions'
89         );
91         $collection->add_subsystem_link('core_files', [], 'privacy:metadata:subsystem:corefiles');
93         return $collection;
94     }
96     /**
97      * Get the list of contexts that contain user information for the specified user.
98      *
99      * @param int $userid The userid.
100      * @return contextlist The list of contexts containing user info for the user.
101      */
102     public static function get_contexts_for_userid(int $userid) : contextlist {
103         $contextlist = new contextlist();
105         // Policies a user has modified.
106         $sql = "SELECT c.id
107                   FROM {context} c
108                   JOIN {tool_policy_versions} v ON v.usermodified = :userid
109                  WHERE c.contextlevel = :contextlevel";
110         $params = [
111             'contextlevel' => CONTEXT_SYSTEM,
112             'userid' => $userid,
113         ];
114         $contextlist->add_from_sql($sql, $params);
116         // Policies a user has accepted.
117         $sql = "SELECT c.id
118                   FROM {context} c
119                   JOIN {tool_policy_acceptances} a ON c.instanceid = a.userid
120                  WHERE
121                     c.contextlevel = :contextlevel
122                    AND (
123                     a.userid = :userid OR a.usermodified = :usermodified
124                    )";
125         $params = [
126             'contextlevel' => CONTEXT_USER,
127             'userid' => $userid,
128             'usermodified' => $userid,
129         ];
130         $contextlist->add_from_sql($sql, $params);
132         return $contextlist;
133     }
135     /**
136      * Export personal data for the given approved_contextlist. User and context information is contained within the contextlist.
137      *
138      * @param approved_contextlist $contextlist A list of contexts approved for export.
139      */
140     public static function export_user_data(approved_contextlist $contextlist) {
141         global $DB;
143         // Export user agreements.
144         foreach ($contextlist->get_contexts() as $context) {
145             if ($context->contextlevel == CONTEXT_USER) {
146                 static::export_policy_agreements_for_context($context);
147             } else if ($context->contextlevel == CONTEXT_SYSTEM) {
148                 static::export_authored_policies($contextlist->get_user());
149             }
150         }
151     }
153     /**
154      * Delete all data for all users in the specified context.
155      *
156      * We never delete user agreements to the policies because they are part of privacy data.
157      * We never delete policy versions because they are part of privacy data.
158      *
159      * @param \context $context The context to delete in.
160      */
161     public static function delete_data_for_all_users_in_context(\context $context) {
162     }
164     /**
165      * Delete all user data for the specified user, in the specified contexts.
166      *
167      * We never delete user agreements to the policies because they are part of privacy data.
168      * We never delete policy versions because they are part of privacy data.
169      *
170      * @param approved_contextlist $contextlist A list of contexts approved for deletion.
171      */
172     public static function delete_data_for_user(approved_contextlist $contextlist) {
173     }
175     /**
176      * Export all policy agreements relating to the specified user context.
177      *
178      * @param \context_user $context The context to export
179      */
180     protected static function export_policy_agreements_for_context(\context_user $context) {
181         global $DB;
183         $sysctx = \context_system::instance();
184         $fs = get_file_storage();
185         $agreementsql = "
186             SELECT
187                 a.id AS agreementid, a.userid, a.timemodified, a.note, a.status,
188                 a.policyversionid AS versionid, a.usermodified, a.timecreated,
189                 v.id, v.archived, v.name, v.revision,
190                 v.summary, v.summaryformat,
191                 v.content, v.contentformat,
192                 p.currentversionid
193              FROM {tool_policy_acceptances} a
194              JOIN {tool_policy_versions} v ON v.id = a.policyversionid
195              JOIN {tool_policy} p ON v.policyid = p.id
196             WHERE a.userid = :userid OR a.usermodified = :usermodified";
198         // Fetch all agreements related to this user.
199         $agreements = $DB->get_recordset_sql($agreementsql, [
200             'userid' => $context->instanceid,
201             'usermodified' => $context->instanceid,
202         ]);
204         $basecontext = [
205             get_string('privacyandpolicies', 'admin'),
206             get_string('useracceptances', 'tool_policy'),
207         ];
209         foreach ($agreements as $agreement) {
210             $subcontext = array_merge($basecontext, [get_string('policynamedversion', 'tool_policy', $agreement)]);
212             $summary = writer::with_context($context)->rewrite_pluginfile_urls(
213                 $subcontext,
214                 'tool_policy',
215                 'policydocumentsummary',
216                 $agreement->versionid,
217                 $agreement->summary
218             );
219             $content = writer::with_context($context)->rewrite_pluginfile_urls(
220                 $subcontext,
221                 'tool_policy',
222                 'policydocumentcontent',
223                 $agreement->versionid,
224                 $agreement->content
225             );
226             $agreementcontent = (object) [
227                 'name' => $agreement->name,
228                 'revision' => $agreement->revision,
229                 'isactive' => transform::yesno($agreement->versionid == $agreement->currentversionid),
230                 'isagreed' => transform::yesno($agreement->status),
231                 'agreedby' => transform::user($agreement->usermodified),
232                 'timecreated' => transform::datetime($agreement->timecreated),
233                 'timemodified' => transform::datetime($agreement->timemodified),
234                 'note' => $agreement->note,
235                 'summary' => format_text($summary, $agreement->summaryformat),
236                 'content' => format_text($content, $agreement->contentformat),
237             ];
239             writer::with_context($context)->export_data($subcontext, $agreementcontent);
240             // Manually export the files as they reside in the system context so we can't use
241             // the write's helper methods.
242             foreach ($fs->get_area_files($sysctx->id, 'tool_policy', 'policydocumentsummary', $agreement->versionid) as $file) {
243                 writer::with_context($context)->export_file($subcontext, $file);
244             }
245             foreach ($fs->get_area_files($sysctx->id, 'tool_policy', 'policydocumentcontent', $agreement->versionid) as $file) {
246                 writer::with_context($context)->export_file($subcontext, $file);
247             }
248         }
249         $agreements->close();
250     }
252     /**
253      * Export all policy agreements that the user authored.
254      *
255      * @param stdClass $user The user who has created the policies to export.
256      */
257     protected static function export_authored_policies(\stdClass $user) {
258         global $DB;
260         // Authored policies are exported against the system.
261         $context = \context_system::instance();
262         $basecontext = [
263             get_string('policydocuments', 'tool_policy'),
264         ];
266         $sql = "SELECT v.id,
267                        v.name,
268                        v.revision,
269                        v.summary,
270                        v.content,
271                        v.archived,
272                        v.usermodified,
273                        v.timecreated,
274                        v.timemodified,
275                        p.currentversionid
276                   FROM {tool_policy_versions} v
277                   JOIN {tool_policy} p ON p.id = v.policyid
278                  WHERE v.usermodified = :userid";
279         $versions = $DB->get_recordset_sql($sql, ['userid' => $user->id]);
280         foreach ($versions as $version) {
281             $subcontext = array_merge($basecontext, [get_string('policynamedversion', 'tool_policy', $version)]);
283             $versioncontent = (object) [
284                 'name' => $version->name,
285                 'revision' => $version->revision,
286                 'summary' => writer::with_context($context)->rewrite_pluginfile_urls(
287                     $subcontext,
288                     'tool_policy',
289                     'policydocumentsummary',
290                     $version->id,
291                     $version->summary
292                 ),
293                 'content' => writer::with_context($context)->rewrite_pluginfile_urls(
294                     $subcontext,
295                     'tool_policy',
296                     'policydocumentcontent',
297                     $version->id,
298                     $version->content
299                 ),
300                 'isactive' => transform::yesno($version->id == $version->currentversionid),
301                 'isarchived' => transform::yesno($version->archived),
302                 'createdbyme' => transform::yesno($version->usermodified == $user->id),
303                 'timecreated' => transform::datetime($version->timecreated),
304                 'timemodified' => transform::datetime($version->timemodified),
305             ];
306             writer::with_context($context)
307                 ->export_data($subcontext, $versioncontent)
308                 ->export_area_files($subcontext, 'tool_policy', 'policydocumentsummary', $version->id)
309                 ->export_area_files($subcontext, 'tool_policy', 'policydocumentcontent', $version->id);
310         }
311         $versions->close();
312     }