Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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/>.
16
 
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
 */
24
 
25
namespace core_grading\privacy;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
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;
35
 
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\plugin\provider,
45
    \core_privacy\local\request\core_userlist_provider,
46
    \core_privacy\local\request\subsystem\provider {
47
 
48
    /**
49
     * Returns meta data about this system.
50
     *
51
     * @param   collection     $collection The initialised collection to add items to.
52
     * @return  collection     A listing of user data stored through this system.
53
     */
54
    public static function get_metadata(collection $collection): collection {
55
        $collection->add_database_table('grading_definitions', [
56
                'method' => 'privacy:metadata:grading_definitions:method',
57
                'areaid' => 'privacy:metadata:grading_definitions:areaid',
58
                'name' => 'privacy:metadata:grading_definitions:name',
59
                'description' => 'privacy:metadata:grading_definitions:description',
60
                'status' => 'privacy:metadata:grading_definitions:status',
61
                'copiedfromid' => 'privacy:metadata:grading_definitions:copiedfromid',
62
                'timecopied' => 'privacy:metadata:grading_definitions:timecopied',
63
                'timecreated' => 'privacy:metadata:grading_definitions:timecreated',
64
                'usercreated' => 'privacy:metadata:grading_definitions:usercreated',
65
                'timemodified' => 'privacy:metadata:grading_definitions:timemodified',
66
                'usermodified' => 'privacy:metadata:grading_definitions:usermodified',
67
                'options' => 'privacy:metadata:grading_definitions:options',
68
            ], 'privacy:metadata:grading_definitions');
69
 
70
        $collection->add_database_table('grading_instances', [
71
                'raterid' => 'privacy:metadata:grading_instances:raterid',
72
                'rawgrade' => 'privacy:metadata:grading_instances:rawgrade',
73
                'status' => 'privacy:metadata:grading_instances:status',
74
                'feedback' => 'privacy:metadata:grading_instances:feedback',
75
                'feedbackformat' => 'privacy:metadata:grading_instances:feedbackformat',
76
                'timemodified' => 'privacy:metadata:grading_instances:timemodified',
77
            ], 'privacy:metadata:grading_instances');
78
 
79
        // Link to subplugin.
80
        $collection->add_plugintype_link('gradingform', [], 'privacy:metadata:gradingformpluginsummary');
81
 
82
        return $collection;
83
    }
84
 
85
    /**
86
     * Get the list of contexts that contain user information for the specified user.
87
     *
88
     * @param int $userid The user to search.
89
     * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
90
     */
91
    public static function get_contexts_for_userid(int $userid): contextlist {
92
        $contextlist = new contextlist();
93
 
94
        $sql = "SELECT c.id
95
                  FROM {context} c
96
                  JOIN {grading_areas} a ON a.contextid = c.id
97
                  JOIN {grading_definitions} d ON d.areaid = a.id
98
             LEFT JOIN {grading_instances} i ON i.definitionid = d.id AND i.raterid = :raterid
99
                 WHERE c.contextlevel = :contextlevel
100
                   AND (d.usercreated = :usercreated OR d.usermodified = :usermodified OR i.id IS NOT NULL)";
101
        $params = [
102
            'usercreated' => $userid,
103
            'usermodified' => $userid,
104
            'raterid' => $userid,
105
            'contextlevel' => CONTEXT_MODULE
106
        ];
107
        $contextlist->add_from_sql($sql, $params);
108
 
109
        return $contextlist;
110
    }
111
 
112
    /**
113
     * Get the list of users who have data within a context.
114
     *
115
     * @param   userlist    $userlist   The userlist containing the list of users who have data in this context/plugin combination.
116
     */
117
    public static function get_users_in_context(\core_privacy\local\request\userlist $userlist) {
118
        $context = $userlist->get_context();
119
        if ($context->contextlevel != CONTEXT_MODULE) {
120
            return;
121
        }
122
 
123
        $params = ['contextid' => $context->id];
124
 
125
        $sql = "SELECT d.usercreated, d.usermodified
126
                  FROM {grading_definitions} d
127
                  JOIN {grading_areas} a ON a.id = d.areaid
128
                  WHERE a.contextid = :contextid";
129
        $userlist->add_from_sql('usercreated', $sql, $params);
130
        $userlist->add_from_sql('usermodified', $sql, $params);
131
 
132
        $sql = "SELECT i.raterid
133
                  FROM {grading_definitions} d
134
                  JOIN {grading_areas} a ON a.id = d.areaid
135
                  JOIN {grading_instances} i ON i.definitionid = d.id
136
                  WHERE a.contextid = :contextid";
137
        $userlist->add_from_sql('raterid', $sql, $params);
138
    }
139
 
140
    /**
141
     * Export all user data for the specified user, in the specified contexts.
142
     *
143
     * @param approved_contextlist $contextlist The approved contexts to export information for.
144
     */
145
    public static function export_user_data(approved_contextlist $contextlist) {
146
        // Remove contexts different from MODULE.
147
        $contexts = array_reduce($contextlist->get_contexts(), function($carry, $context) {
148
            if ($context->contextlevel == CONTEXT_MODULE) {
149
                $carry[] = $context;
150
            }
151
            return $carry;
152
        }, []);
153
 
154
        if (empty($contexts)) {
155
            return;
156
        }
157
 
158
        $userid = $contextlist->get_user()->id;
159
        $subcontext = [get_string('gradingmethod', 'grading')];
160
        foreach ($contexts as $context) {
161
            // Export grading definitions created or modified on this context.
162
            self::export_definitions($context, $subcontext, $userid);
163
        }
164
    }
165
 
166
    /**
167
     * Export all user data related to a context and itemid.
168
     *
169
     * @param  \context $context    Context to export on.
170
     * @param  int      $itemid     Item ID to export on.
171
     * @param  array    $subcontext Directory location to export to.
172
     */
173
    public static function export_item_data(\context $context, int $itemid, array $subcontext) {
174
        global $DB;
175
 
176
        $sql = "SELECT gi.id AS instanceid, gd.id AS definitionid, gd.method
177
                  FROM {grading_areas} ga
178
                  JOIN {grading_definitions} gd ON gd.areaid = ga.id
179
                  JOIN {grading_instances} gi ON gi.definitionid = gd.id AND gi.itemid = :itemid
180
                 WHERE ga.contextid = :contextid";
181
        $params = [
182
            'itemid' => $itemid,
183
            'contextid' => $context->id,
184
        ];
185
        $records = $DB->get_recordset_sql($sql, $params);
186
        foreach ($records as $record) {
187
            $instancedata = manager::component_class_callback(
188
                "gradingform_{$record->method}",
189
                gradingform_provider_v2::class,
190
                'export_gradingform_instance_data',
191
                [$context, $record->instanceid, $subcontext]
192
            );
193
        }
194
        $records->close();
195
    }
196
 
197
    /**
198
     * Deletes all user data related to a context and possibly an itemid.
199
     *
200
     * @param  \context $context The context to delete on.
201
     * @param  int|null $itemid  An optional item ID to refine the deletion.
202
     */
203
    public static function delete_instance_data(\context $context, int $itemid = null) {
204
        if (is_null($itemid)) {
205
            self::delete_data_for_instances($context);
206
        } else {
207
            self::delete_data_for_instances($context, [$itemid]);
208
        }
209
    }
210
 
211
    /**
212
     * Deletes all user data related to a context and possibly itemids.
213
     *
214
     * @param  \context $context The context to delete on.
215
     * @param  array $itemids  An optional list of item IDs to refine the deletion.
216
     */
217
    public static function delete_data_for_instances(\context $context, array $itemids = []) {
218
        global $DB;
219
        $itemsql = '';
220
        $params = ['contextid' => $context->id];
221
        if (!empty($itemids)) {
222
            list($itemsql, $itemparams) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED);
223
            $params = array_merge($params, $itemparams);
224
            $itemsql = "AND itemid $itemsql";
225
        }
226
        $sql = "SELECT gi.id AS instanceid, gd.id, gd.method
227
                  FROM {grading_definitions} gd
228
                  JOIN {grading_instances} gi ON gi.definitionid = gd.id
229
                  JOIN {grading_areas} ga ON ga.id = gd.areaid
230
                 WHERE ga.contextid = :contextid $itemsql";
231
        $records = $DB->get_records_sql($sql, $params);
232
        if ($records) {
233
            $firstrecord = current($records);
234
            $method = $firstrecord->method;
235
            $instanceids = array_map(function($record) {
236
                return $record->instanceid;
237
            }, $records);
238
            manager::component_class_callback(
239
                "gradingform_{$method}",
240
                gradingform_provider_v2::class,
241
                'delete_gradingform_for_instances',
242
                [$instanceids]);
243
            // Delete grading_instances rows.
244
            $DB->delete_records_list('grading_instances', 'id', $instanceids);
245
        }
246
    }
247
 
248
    /**
249
     * Exports the data related to grading definitions within the specified context/subcontext.
250
     *
251
     * @param  \context         $context Context owner of the data.
252
     * @param  array            $subcontext Subcontext owner of the data.
253
     * @param  int              $userid The user whose information is to be exported.
254
     */
255
    protected static function export_definitions(\context $context, array $subcontext, int $userid = 0) {
256
        global $DB;
257
 
258
        $join = "JOIN {grading_areas} a ON a.id = d.areaid
259
                 JOIN {context} c ON a.contextid = c.id AND c.contextlevel = :contextlevel";
260
        $select = 'a.contextid = :contextid';
261
        $params = [
262
            'contextlevel' => CONTEXT_MODULE,
263
            'contextid'    => $context->id
264
        ];
265
 
266
        if (!empty($userid)) {
267
            $join .= ' LEFT JOIN {grading_instances} i ON i.definitionid = d.id AND i.raterid = :raterid';
268
            $select .= ' AND (usercreated = :usercreated
269
                OR usermodified = :usermodified OR i.id IS NOT NULL)';
270
            $params['usercreated'] = $userid;
271
            $params['usermodified'] = $userid;
272
            $params['raterid'] = $userid;
273
        }
274
 
275
        $sql = "SELECT gd.id,
276
                       gd.method,
277
                       gd.name,
278
                       gd.description,
279
                       gd.timecopied,
280
                       gd.timecreated,
281
                       gd.usercreated,
282
                       gd.timemodified,
283
                       gd.usermodified
284
                  FROM (
285
                        SELECT DISTINCT d.id
286
                                   FROM {grading_definitions} d
287
                                  $join
288
                                  WHERE $select
289
                  ) ids
290
                  JOIN {grading_definitions} gd ON gd.id = ids.id";
291
        $definitions = $DB->get_recordset_sql($sql, $params);
292
        $defdata = [];
293
        foreach ($definitions as $definition) {
294
            $tmpdata = [
295
                'method' => $definition->method,
296
                'name' => $definition->name,
297
                'description' => $definition->description,
298
                'timecreated' => transform::datetime($definition->timecreated),
299
                'usercreated' => transform::user($definition->usercreated),
300
                'timemodified' => transform::datetime($definition->timemodified),
301
                'usermodified' => transform::user($definition->usermodified),
302
            ];
303
            if (!empty($definition->timecopied)) {
304
                $tmpdata['timecopied'] = transform::datetime($definition->timecopied);
305
            }
306
 
307
            $defdata[] = (object) $tmpdata;
308
 
309
            // Export grading_instances information.
310
            self::export_grading_instances($context, $subcontext, $definition->id, $userid);
311
        }
312
        $definitions->close();
313
 
314
        if (!empty($defdata)) {
315
            $data = (object) [
316
                'definitions' => $defdata,
317
            ];
318
 
319
            writer::with_context($context)->export_data($subcontext, $data);
320
        }
321
    }
322
 
323
    /**
324
     * Exports the data related to grading instances within the specified definition.
325
     *
326
     * @param  \context         $context Context owner of the data.
327
     * @param  array            $subcontext Subcontext owner of the data.
328
     * @param  int              $definitionid The definition ID whose grading instance information is to be exported.
329
     * @param  int              $userid The user whose information is to be exported.
330
     */
331
    protected static function export_grading_instances(\context $context, array $subcontext, int $definitionid, int $userid = 0) {
332
        global $DB;
333
 
334
        $params = ['definitionid' => $definitionid];
335
        if (!empty($userid)) {
336
            $params['raterid'] = $userid;
337
        }
338
        $instances = $DB->get_recordset('grading_instances', $params);
339
        $instancedata = [];
340
        foreach ($instances as $instance) {
341
            // TODO: Get the status name (instead of the ID).
342
            $tmpdata = [
343
                'rawgrade' => $instance->rawgrade,
344
                'status' => $instance->status,
345
                'feedback' => $instance->feedback,
346
                'feedbackformat' => $instance->feedbackformat,
347
                'timemodified' => transform::datetime($instance->timemodified),
348
            ];
349
            $instancedata[] = (object) $tmpdata;
350
        }
351
        $instances->close();
352
 
353
        if (!empty($instancedata)) {
354
            $data = (object) [
355
                'instances' => $instancedata,
356
            ];
357
 
358
            writer::with_context($context)->export_related_data($subcontext, 'gradinginstances', $data);
359
        }
360
    }
361
 
362
    /**
363
     * No deletion of the advanced grading is done.
364
     *
365
     * @param \context $context the context to delete in.
366
     */
367
    public static function delete_data_for_all_users_in_context(\context $context) {
368
        // The only information left to be deleted here is the grading definitions. Currently we are not deleting these.
369
    }
370
 
371
    /**
372
     * Deletion of data in this provider is only related to grades and so can not be
373
     * deleted for the creator of the advanced grade criteria.
374
     *
375
     * @param approved_contextlist $contextlist a list of contexts approved for deletion.
376
     */
377
    public static function delete_data_for_user(approved_contextlist $contextlist) {
378
        // The only information left to be deleted here is the grading definitions. Currently we are not deleting these.
379
    }
380
 
381
    /**
382
     * Delete multiple users within a single context.
383
     *
384
     * @param approved_userlist $userlist The approved context and user information to delete information for.
385
     */
386
    public static function delete_data_for_users(\core_privacy\local\request\approved_userlist $userlist) {
387
        // The only information left to be deleted here is the grading definitions. Currently we are not deleting these.
388
    }
389
}