73f632f6a0fd033938395c1bed08f9be6351a1ae
[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 DISTINCT d.id,
164                                 d.method,
165                                 d.name,
166                                 d.description,
167                                 d.timecopied,
168                                 d.timecreated,
169                                 d.usercreated,
170                                 d.timemodified,
171                                 d.usermodified
172                            FROM {grading_definitions} d
173                            $join
174                            WHERE $select";
175         $definitions = $DB->get_recordset_sql($sql, $params);
176         $defdata = [];
177         foreach ($definitions as $definition) {
178             $tmpdata = [
179                 'method' => $definition->method,
180                 'name' => $definition->name,
181                 'description' => $definition->description,
182                 'timecreated' => transform::datetime($definition->timecreated),
183                 'usercreated' => transform::user($definition->usercreated),
184                 'timemodified' => transform::datetime($definition->timemodified),
185                 'usermodified' => transform::user($definition->usermodified),
186             ];
187             if (!empty($definition->timecopied)) {
188                 $tmpdata['timecopied'] = transform::datetime($definition->timecopied);
189             }
190             // Export gradingform information (if needed).
191             $instancedata = manager::component_class_callback(
192                 "gradingform_{$definition->method}",
193                 gradingform_provider::class,
194                 'get_gradingform_export_data',
195                 [$context, $definition, $userid]
196             );
197             if (null !== $instancedata) {
198                 $tmpdata = array_merge($tmpdata, $instancedata);
199             }
201             $defdata[] = (object) $tmpdata;
203             // Export grading_instances information.
204             self::export_grading_instances($context, $subcontext, $definition->id, $userid);
205         }
206         $definitions->close();
208         if (!empty($defdata)) {
209             $data = (object) [
210                 'definitions' => $defdata,
211             ];
213             writer::with_context($context)->export_data($subcontext, $data);
214         }
215     }
217     /**
218      * Exports the data related to grading instances within the specified definition.
219      *
220      * @param  \context         $context Context owner of the data.
221      * @param  array            $subcontext Subcontext owner of the data.
222      * @param  int              $definitionid The definition ID whose grading instance information is to be exported.
223      * @param  int              $userid The user whose information is to be exported.
224      */
225     protected static function export_grading_instances(\context $context, array $subcontext, int $definitionid, int $userid = 0) {
226         global $DB;
228         $params = ['definitionid' => $definitionid];
229         if (!empty($userid)) {
230             $params['raterid'] = $userid;
231         }
232         $instances = $DB->get_recordset('grading_instances', $params);
233         $instancedata = [];
234         foreach ($instances as $instance) {
235             // TODO: Get the status name (instead of the ID).
236             $tmpdata = [
237                 'rawgrade' => $instance->rawgrade,
238                 'status' => $instance->status,
239                 'feedback' => $instance->feedback,
240                 'feedbackformat' => $instance->feedbackformat,
241                 'timemodified' => transform::datetime($instance->timemodified),
242             ];
243             $instancedata[] = (object) $tmpdata;
244         }
245         $instances->close();
247         if (!empty($instancedata)) {
248             $data = (object) [
249                 'instances' => $instancedata,
250             ];
252             writer::with_context($context)->export_related_data($subcontext, 'gradinginstances', $data);
253         }
254     }
256     /**
257      * Delete all use data which matches the specified $context.
258      *
259      * We never delete grading content.
260      *
261      * @param context $context A user context.
262      */
263     public static function delete_data_for_all_users_in_context(\context $context) {
264         manager::plugintype_class_callback(
265             'gradingform',
266             gradingform_provider::class,
267             'delete_gradingform_for_context',
268             [$context]
269         );
270     }
272     /**
273      * Delete all user data for the specified user, in the specified contexts.
274      *
275      * We never delete grading content.
276      *
277      * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
278      */
279     public static function delete_data_for_user(approved_contextlist $contextlist) {
280         manager::plugintype_class_callback(
281             'gradingform',
282             gradingform_provider::class,
283             'delete_gradingform_for_userid',
284             [$contextlist]
285         );
286     }