490cc791dd2d336e78f3d75a8ff3cc898e8cc878
[moodle.git] / grade / grading / 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 class for requesting user data.
19  *
20  * @package    core_grading
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 core_grading\privacy;
27 defined('MOODLE_INTERNAL') || die();
29 use \core_privacy\local\metadata\collection;
30 use \core_privacy\local\request\approved_contextlist;
31 use \core_privacy\local\request\contextlist;
32 use \core_privacy\local\request\transform;
33 use \core_privacy\local\request\writer;
34 use \core_privacy\manager;
36 /**
37  * Privacy class for requesting user data.
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     \core_privacy\local\metadata\provider,
44     \core_privacy\local\request\subsystem\provider {
46     /**
47      * Returns meta data about this system.
48      *
49      * @param   collection     $collection The initialised collection to add items to.
50      * @return  collection     A listing of user data stored through this system.
51      */
52     public static function get_metadata(collection $collection) : collection {
53         $collection->add_database_table('grading_definitions', [
54                 'method' => 'privacy:metadata:grading_definitions:method',
55                 'areaid' => 'privacy:metadata:grading_definitions:areaid',
56                 'name' => 'privacy:metadata:grading_definitions:name',
57                 'description' => 'privacy:metadata:grading_definitions:description',
58                 'status' => 'privacy:metadata:grading_definitions:status',
59                 'copiedfromid' => 'privacy:metadata:grading_definitions:copiedfromid',
60                 'timecopied' => 'privacy:metadata:grading_definitions:timecopied',
61                 'timecreated' => 'privacy:metadata:grading_definitions:timecreated',
62                 'usercreated' => 'privacy:metadata:grading_definitions:usercreated',
63                 'timemodified' => 'privacy:metadata:grading_definitions:timemodified',
64                 'usermodified' => 'privacy:metadata:grading_definitions:usermodified',
65                 'options' => 'privacy:metadata:grading_definitions:options',
66             ], 'privacy:metadata:grading_definitions');
68         $collection->add_database_table('grading_instances', [
69                 'raterid' => 'privacy:metadata:grading_instances:raterid',
70                 'rawgrade' => 'privacy:metadata:grading_instances:rawgrade',
71                 'status' => 'privacy:metadata:grading_instances:status',
72                 'feedback' => 'privacy:metadata:grading_instances:feedback',
73                 'feedbackformat' => 'privacy:metadata:grading_instances:feedbackformat',
74                 'timemodified' => 'privacy:metadata:grading_instances:timemodified',
75             ], 'privacy:metadata:grading_instances');
77         // Link to subplugin.
78         $collection->add_plugintype_link('gradingform', [], 'privacy:metadata:gradingformpluginsummary');
80         return $collection;
81     }
83     /**
84      * Get the list of contexts that contain user information for the specified user.
85      *
86      * @param int $userid The user to search.
87      * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
88      */
89     public static function get_contexts_for_userid(int $userid) : contextlist {
90         $contextlist = new contextlist();
92         $sql = "SELECT c.id
93                   FROM {context} c
94                   JOIN {grading_areas} a ON a.contextid = c.id
95                   JOIN {grading_definitions} d ON d.areaid = a.id
96              LEFT JOIN {grading_instances} i ON i.definitionid = d.id AND i.raterid = :raterid
97                  WHERE c.contextlevel = :contextlevel
98                    AND (d.usercreated = :usercreated OR d.usermodified = :usermodified OR i.id IS NOT NULL)";
99         $params = [
100             'usercreated' => $userid,
101             'usermodified' => $userid,
102             'raterid' => $userid,
103             'contextlevel' => CONTEXT_MODULE
104         ];
105         $contextlist->add_from_sql($sql, $params);
107         return $contextlist;
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         // Remove contexts different from MODULE.
117         $contexts = array_reduce($contextlist->get_contexts(), function($carry, $context) {
118             if ($context->contextlevel == CONTEXT_MODULE) {
119                 $carry[] = $context;
120             }
121             return $carry;
122         }, []);
124         if (empty($contexts)) {
125             return;
126         }
128         $userid = $contextlist->get_user()->id;
129         $subcontext = [get_string('gradingmethod', 'grading')];
130         foreach ($contexts as $context) {
131             // Export grading definitions created or modified on this context.
132             self::export_definitions($context, $subcontext, $userid);
133         }
134     }
136     /**
137      * Exports the data related to grading definitions within the specified context/subcontext.
138      *
139      * @param  \context         $context Context owner of the data.
140      * @param  array            $subcontext Subcontext owner of the data.
141      * @param  int              $userid The user whose information is to be exported.
142      */
143     protected static function export_definitions(\context $context, array $subcontext, int $userid = 0) {
144         global $DB;
146         $join = "JOIN {grading_areas} a ON a.id = d.areaid
147                  JOIN {context} c ON a.contextid = c.id AND c.contextlevel = :contextlevel";
148         $select = 'a.contextid = :contextid';
149         $params = [
150             'contextlevel' => CONTEXT_MODULE,
151             'contextid'    => $context->id
152         ];
154         if (!empty($userid)) {
155             $join .= ' LEFT JOIN {grading_instances} i ON i.definitionid = d.id AND i.raterid = :raterid';
156             $select .= ' AND (usercreated = :usercreated
157                 OR usermodified = :usermodified OR i.id IS NOT NULL)';
158             $params['usercreated'] = $userid;
159             $params['usermodified'] = $userid;
160             $params['raterid'] = $userid;
161         }
163         $sql = "SELECT gd.id,
164                        gd.method,
165                        gd.name,
166                        gd.description,
167                        gd.timecopied,
168                        gd.timecreated,
169                        gd.usercreated,
170                        gd.timemodified,
171                        gd.usermodified
172                   FROM (
173                         SELECT DISTINCT d.id
174                                    FROM {grading_definitions} d
175                                   $join
176                                   WHERE $select
177                   ) ids
178                   JOIN {grading_definitions} gd ON gd.id = ids.id";
179         $definitions = $DB->get_recordset_sql($sql, $params);
180         $defdata = [];
181         foreach ($definitions as $definition) {
182             $tmpdata = [
183                 'method' => $definition->method,
184                 'name' => $definition->name,
185                 'description' => $definition->description,
186                 'timecreated' => transform::datetime($definition->timecreated),
187                 'usercreated' => transform::user($definition->usercreated),
188                 'timemodified' => transform::datetime($definition->timemodified),
189                 'usermodified' => transform::user($definition->usermodified),
190             ];
191             if (!empty($definition->timecopied)) {
192                 $tmpdata['timecopied'] = transform::datetime($definition->timecopied);
193             }
194             // Export gradingform information (if needed).
195             $instancedata = manager::component_class_callback(
196                 "gradingform_{$definition->method}",
197                 gradingform_provider::class,
198                 'get_gradingform_export_data',
199                 [$context, $definition, $userid]
200             );
201             if (null !== $instancedata) {
202                 $tmpdata = array_merge($tmpdata, $instancedata);
203             }
205             $defdata[] = (object) $tmpdata;
207             // Export grading_instances information.
208             self::export_grading_instances($context, $subcontext, $definition->id, $userid);
209         }
210         $definitions->close();
212         if (!empty($defdata)) {
213             $data = (object) [
214                 'definitions' => $defdata,
215             ];
217             writer::with_context($context)->export_data($subcontext, $data);
218         }
219     }
221     /**
222      * Exports the data related to grading instances within the specified definition.
223      *
224      * @param  \context         $context Context owner of the data.
225      * @param  array            $subcontext Subcontext owner of the data.
226      * @param  int              $definitionid The definition ID whose grading instance information is to be exported.
227      * @param  int              $userid The user whose information is to be exported.
228      */
229     protected static function export_grading_instances(\context $context, array $subcontext, int $definitionid, int $userid = 0) {
230         global $DB;
232         $params = ['definitionid' => $definitionid];
233         if (!empty($userid)) {
234             $params['raterid'] = $userid;
235         }
236         $instances = $DB->get_recordset('grading_instances', $params);
237         $instancedata = [];
238         foreach ($instances as $instance) {
239             // TODO: Get the status name (instead of the ID).
240             $tmpdata = [
241                 'rawgrade' => $instance->rawgrade,
242                 'status' => $instance->status,
243                 'feedback' => $instance->feedback,
244                 'feedbackformat' => $instance->feedbackformat,
245                 'timemodified' => transform::datetime($instance->timemodified),
246             ];
247             $instancedata[] = (object) $tmpdata;
248         }
249         $instances->close();
251         if (!empty($instancedata)) {
252             $data = (object) [
253                 'instances' => $instancedata,
254             ];
256             writer::with_context($context)->export_related_data($subcontext, 'gradinginstances', $data);
257         }
258     }
260     /**
261      * Delete all use data which matches the specified $context.
262      *
263      * We never delete grading content.
264      *
265      * @param context $context A user context.
266      */
267     public static function delete_data_for_all_users_in_context(\context $context) {
268         manager::plugintype_class_callback(
269             'gradingform',
270             gradingform_provider::class,
271             'delete_gradingform_for_context',
272             [$context]
273         );
274     }
276     /**
277      * Delete all user data for the specified user, in the specified contexts.
278      *
279      * We never delete grading content.
280      *
281      * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
282      */
283     public static function delete_data_for_user(approved_contextlist $contextlist) {
284         manager::plugintype_class_callback(
285             'gradingform',
286             gradingform_provider::class,
287             'delete_gradingform_for_userid',
288             [$contextlist]
289         );
290     }