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
namespace mod_questionnaire\privacy;
18
 
19
use \core_privacy\local\metadata\collection;
20
use \core_privacy\local\request\contextlist;
21
use \core_privacy\local\request\userlist;
22
use \core_privacy\local\request\approved_contextlist;
23
use \core_privacy\local\request\approved_userlist;
24
 
25
/**
26
 * Contains class mod_questionnaire\privacy\provider
27
 *
28
 * @package    mod_questionnaire
29
 * @copyright  2018 onward Mike Churchward (mike.churchward@poetopensource.org)
30
 * @author     Mike Churchward
31
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32
 */
33
class provider implements
34
    // This plugin has data.
35
    \core_privacy\local\metadata\provider,
36
 
37
    // This plugin is capable of determining which users have data within it.
38
    \core_privacy\local\request\core_userlist_provider,
39
 
40
    // This plugin currently implements the original plugin_provider interface.
41
    \core_privacy\local\request\plugin\provider {
42
 
43
    /**
44
     * Returns meta data about this system.
45
     *
46
     * @param   collection $collection The collection to add metadata to.
47
     * @return  collection  The array of metadata
48
     */
49
    public static function get_metadata(collection $collection): collection {
50
 
51
        // Add all of the relevant tables and fields to the collection.
52
        $collection->add_database_table('questionnaire_response', [
53
            'userid' => 'privacy:metadata:questionnaire_response:userid',
54
            'questionnaireid' => 'privacy:metadata:questionnaire_response:questionnaireid',
55
            'complete' => 'privacy:metadata:questionnaire_response:complete',
56
            'grade' => 'privacy:metadata:questionnaire_response:grade',
57
            'submitted' => 'privacy:metadata:questionnaire_response:submitted',
58
        ], 'privacy:metadata:questionnaire_response');
59
 
60
        $collection->add_database_table('questionnaire_response_bool', [
61
            'response_id' => 'privacy:metadata:questionnaire_response_bool:response_id',
62
            'question_id' => 'privacy:metadata:questionnaire_response_bool:question_id',
63
            'choice_id' => 'privacy:metadata:questionnaire_response_bool:choice_id',
64
        ], 'privacy:metadata:questionnaire_response_bool');
65
 
66
        $collection->add_database_table('questionnaire_response_date', [
67
            'response_id' => 'privacy:metadata:questionnaire_response_date:response_id',
68
            'question_id' => 'privacy:metadata:questionnaire_response_date:question_id',
69
            'response' => 'privacy:metadata:questionnaire_response_date:response',
70
        ], 'privacy:metadata:questionnaire_response_date');
71
 
72
        $collection->add_database_table('questionnaire_response_other', [
73
            'response_id' => 'privacy:metadata:questionnaire_response_other:response_id',
74
            'question_id' => 'privacy:metadata:questionnaire_response_other:question_id',
75
            'choice_id' => 'privacy:metadata:questionnaire_response_other:choice_id',
76
            'response' => 'privacy:metadata:questionnaire_response_other:response',
77
        ], 'privacy:metadata:questionnaire_response_other');
78
 
79
        $collection->add_database_table('questionnaire_response_rank', [
80
            'response_id' => 'privacy:metadata:questionnaire_response_rank:response_id',
81
            'question_id' => 'privacy:metadata:questionnaire_response_rank:question_id',
82
            'choice_id' => 'privacy:metadata:questionnaire_response_rank:choice_id',
83
            'rank' => 'privacy:metadata:questionnaire_response_rank:rankvalue',
84
        ], 'privacy:metadata:questionnaire_response_rank');
85
 
86
        $collection->add_database_table('questionnaire_response_text', [
87
            'response_id' => 'privacy:metadata:questionnaire_response_text:response_id',
88
            'question_id' => 'privacy:metadata:questionnaire_response_text:question_id',
89
            'response' => 'privacy:metadata:questionnaire_response_text:response',
90
        ], 'privacy:metadata:questionnaire_response_text');
91
 
92
        $collection->add_database_table('questionnaire_resp_multiple', [
93
            'response_id' => 'privacy:metadata:questionnaire_resp_multiple:response_id',
94
            'question_id' => 'privacy:metadata:questionnaire_resp_multiple:question_id',
95
            'choice_id' => 'privacy:metadata:questionnaire_resp_multiple:choice_id',
96
        ], 'privacy:metadata:questionnaire_resp_multiple');
97
 
98
        $collection->add_database_table('questionnaire_resp_single', [
99
            'response_id' => 'privacy:metadata:questionnaire_resp_single:response_id',
100
            'question_id' => 'privacy:metadata:questionnaire_resp_single:question_id',
101
            'choice_id' => 'privacy:metadata:questionnaire_resp_single:choice_id',
102
        ], 'privacy:metadata:questionnaire_resp_single');
103
 
104
        return $collection;
105
    }
106
 
107
    /**
108
     * Get the list of contexts that contain user information for the specified user.
109
     *
110
     * @param   int $userid The user to search.
111
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.
112
     */
113
    public static function get_contexts_for_userid(int $userid): contextlist {
114
        $contextlist = new contextlist();
115
 
116
        $sql = "SELECT c.id
117
             FROM {context} c
118
       INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
119
       INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
120
       INNER JOIN {questionnaire} q ON q.id = cm.instance
121
       INNER JOIN {questionnaire_response} qr ON qr.questionnaireid = q.id
122
            WHERE qr.userid = :attemptuserid
123
       ";
124
 
125
        $params = [
126
            'modname' => 'questionnaire',
127
            'contextlevel' => CONTEXT_MODULE,
128
            'attemptuserid' => $userid,
129
        ];
130
 
131
        $contextlist->add_from_sql($sql, $params);
132
 
133
        return $contextlist;
134
    }
135
 
136
    /**
137
     * Get the list of users who have data within a context.
138
     *
139
     * @param \core_privacy\local\request\userlist $userlist The userlist containing the list of users who have data in this
140
     * context/plugin combination.
141
     */
142
    public static function get_users_in_context(userlist $userlist) {
143
 
144
        $context = $userlist->get_context();
145
        if (!$context instanceof \context_module) {
146
            return;
147
        }
148
 
149
        $params = ['modulename' => 'questionnaire', 'instanceid' => $context->instanceid];
150
 
151
        // Questionnaire respondents.
152
        $sql = "SELECT qr.userid
153
              FROM {course_modules} cm
154
              JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
155
              JOIN {questionnaire} q ON q.id = cm.instance
156
              JOIN {questionnaire_response} qr ON qr.questionnaireid = q.id
157
             WHERE cm.id = :instanceid";
158
        $userlist->add_from_sql('userid', $sql, $params);
159
    }
160
 
161
    /**
162
     * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.
163
     *
164
     * @param   approved_contextlist $contextlist The approved contexts to export information for.
165
     */
166
    public static function export_user_data(approved_contextlist $contextlist) {
167
        global $DB, $CFG;
168
        require_once($CFG->dirroot . '/mod/questionnaire/questionnaire.class.php');
169
 
170
        if (empty($contextlist->count())) {
171
            return;
172
        }
173
 
174
        $user = $contextlist->get_user();
175
 
176
        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
177
 
178
        $sql = "SELECT cm.id AS cmid,
179
                   q.id AS qid, q.course AS qcourse,
180
                   qr.id AS responseid, qr.submitted AS lastsaved, qr.complete AS complete
181
              FROM {context} c
182
        INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
183
        INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
184
        INNER JOIN {questionnaire} q ON q.id = cm.instance
185
        INNER JOIN {questionnaire_response} qr ON qr.questionnaireid = q.id
186
             WHERE c.id {$contextsql}
187
                   AND qr.userid = :userid
188
          ORDER BY cm.id, qr.id ASC";
189
 
190
        $params = ['modname' => 'questionnaire', 'contextlevel' => CONTEXT_MODULE, 'userid' => $user->id] + $contextparams;
191
 
192
        // There can be more than one attempt per instance, so we'll gather them by cmid.
193
        $lastcmid = 0;
194
        $responsedata = [];
195
        $responses = $DB->get_recordset_sql($sql, $params);
196
        foreach ($responses as $response) {
197
            // If we've moved to a new choice, then write the last choice data and reinit the choice data array.
198
            if ($lastcmid != $response->cmid) {
199
                if (!empty($responsedata)) {
200
                    $context = \context_module::instance($lastcmid);
201
                    // Fetch the generic module data for the questionnaire.
202
                    $contextdata = \core_privacy\local\request\helper::get_context_data($context, $user);
203
                    // Merge with attempt data and write it.
204
                    $contextdata = (object)array_merge((array)$contextdata, $responsedata);
205
                    \core_privacy\local\request\writer::with_context($context)->export_data([], $contextdata);
206
                }
207
                $responsedata = [];
208
                $lastcmid = $response->cmid;
209
                $course = $DB->get_record("course", ["id" => $response->qcourse]);
210
                $cm = get_coursemodule_from_instance("questionnaire", $response->qid, $course->id);
211
                $questionnaire = new \questionnaire($course, $cm, $response->qid, null);
212
            }
213
            $responsedata['responses'][] = [
214
                'complete' => (($response->complete == 'y') ? get_string('yes') : get_string('no')),
215
                'lastsaved' => \core_privacy\local\request\transform::datetime($response->lastsaved),
216
                'questions' => $questionnaire->get_structured_response($response->responseid),
217
            ];
218
        }
219
        $responses->close();
220
 
221
        // The data for the last activity won't have been written yet, so make sure to write it now!
222
        if (!empty($responsedata)) {
223
            $context = \context_module::instance($lastcmid);
224
            // Fetch the generic module data for the questionnaire.
225
            $contextdata = \core_privacy\local\request\helper::get_context_data($context, $user);
226
            // Merge with attempt data and write it.
227
            $contextdata = (object)array_merge((array)$contextdata, $responsedata);
228
            \core_privacy\local\request\writer::with_context($context)->export_data([], $contextdata);
229
        }
230
    }
231
 
232
    /**
233
     * Delete all personal data for all users in the specified context.
234
     *
235
     * @param context $context Context to delete data from.
236
     */
237
    public static function delete_data_for_all_users_in_context(\context $context) {
238
        global $DB;
239
 
240
        if (!($context instanceof \context_module)) {
241
            return;
242
        }
243
 
244
        if (!$cm = get_coursemodule_from_id('questionnaire', $context->instanceid)) {
245
            return;
246
        }
247
 
248
        if (!($questionnaire = $DB->get_record('questionnaire', ['id' => $cm->instance]))) {
249
            return;
250
        }
251
 
252
        if ($responses = $DB->get_recordset('questionnaire_response', ['questionnaireid' => $questionnaire->id])) {
253
            self::delete_responses($responses);
254
        }
255
        $responses->close();
256
        $DB->delete_records('questionnaire_response', ['questionnaireid' => $questionnaire->id]);
257
    }
258
 
259
    /**
260
     * Delete all user data for the specified user, in the specified contexts.
261
     *
262
     * @param   approved_contextlist $contextlist The approved contexts and user information to delete information for.
263
     */
264
    public static function delete_data_for_user(approved_contextlist $contextlist) {
265
        global $DB;
266
 
267
        if (empty($contextlist->count())) {
268
            return;
269
        }
270
 
271
        $userid = $contextlist->get_user()->id;
272
        foreach ($contextlist->get_contexts() as $context) {
273
            if (!($context instanceof \context_module)) {
274
                continue;
275
            }
276
            if (!$cm = get_coursemodule_from_id('questionnaire', $context->instanceid)) {
277
                continue;
278
            }
279
 
280
            if (!($questionnaire = $DB->get_record('questionnaire', ['id' => $cm->instance]))) {
281
                continue;
282
            }
283
 
284
            if ($responses = $DB->get_recordset('questionnaire_response',
285
                ['questionnaireid' => $questionnaire->id, 'userid' => $userid])) {
286
                self::delete_responses($responses);
287
            }
288
            $responses->close();
289
            $DB->delete_records('questionnaire_response', ['questionnaireid' => $questionnaire->id, 'userid' => $userid]);
290
        }
291
    }
292
 
293
    /**
294
     * Delete multiple users within a single context.
295
     *
296
     * @param \core_privacy\local\request\approved_userlist $userlist The approved context and user information to delete
297
     * information for.
298
     */
299
    public static function delete_data_for_users(approved_userlist $userlist) {
300
        global $DB;
301
 
302
        $context = $userlist->get_context();
303
        if (!$cm = get_coursemodule_from_id('questionnaire', $context->instanceid)) {
304
            return;
305
        }
306
        if (!($questionnaire = $DB->get_record('questionnaire', ['id' => $cm->instance]))) {
307
            return;
308
        }
309
 
310
        list($userinsql, $userinparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
311
        $params = array_merge(['questionnaireid' => $questionnaire->id], $userinparams);
312
        $select = 'questionnaireid = :questionnaireid AND userid ' . $userinsql;
313
        if ($responses = $DB->get_recordset_select('questionnaire_response', $select, $params)) {
314
            self::delete_responses($responses);
315
        }
316
        $responses->close();
317
        $DB->delete_records_select('questionnaire_response', $select, $params);
318
    }
319
 
320
    /**
321
     * Helper function to delete all the response records for a recordset array of responses.
322
     *
323
     * @param \moodle_recordset $responses The list of response records to delete for.
324
     */
325
    private static function delete_responses(\moodle_recordset $responses) {
326
        global $DB;
327
 
328
        foreach ($responses as $response) {
329
            $DB->delete_records('questionnaire_response_bool', ['response_id' => $response->id]);
330
            $DB->delete_records('questionnaire_response_date', ['response_id' => $response->id]);
331
            $DB->delete_records('questionnaire_resp_multiple', ['response_id' => $response->id]);
332
            $DB->delete_records('questionnaire_response_other', ['response_id' => $response->id]);
333
            $DB->delete_records('questionnaire_response_rank', ['response_id' => $response->id]);
334
            $DB->delete_records('questionnaire_resp_single', ['response_id' => $response->id]);
335
            $DB->delete_records('questionnaire_response_text', ['response_id' => $response->id]);
336
        }
337
    }
338
}