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 Subsystem implementation for mod_choice.
19
 *
20
 * @package    mod_choice
21
 * @category   privacy
22
 * @copyright  2018 Jun Pataleta
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 */
25
 
26
namespace mod_choice\privacy;
27
 
28
use core_privacy\local\metadata\collection;
29
use core_privacy\local\request\approved_contextlist;
30
use core_privacy\local\request\approved_userlist;
31
use core_privacy\local\request\contextlist;
32
use core_privacy\local\request\deletion_criteria;
33
use core_privacy\local\request\helper;
34
use core_privacy\local\request\userlist;
35
use core_privacy\local\request\writer;
36
 
37
defined('MOODLE_INTERNAL') || die();
38
 
39
/**
40
 * Implementation of the privacy subsystem plugin provider for the choice activity module.
41
 *
42
 * @copyright  2018 Jun Pataleta
43
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44
 */
45
class provider implements
46
        // This plugin stores personal data.
47
        \core_privacy\local\metadata\provider,
48
 
49
        // This plugin is a core_user_data_provider.
50
        \core_privacy\local\request\plugin\provider,
51
 
52
        // This plugin is capable of determining which users have data within it.
53
        \core_privacy\local\request\core_userlist_provider {
54
    /**
55
     * Return the fields which contain personal data.
56
     *
57
     * @param collection $items a reference to the collection to use to store the metadata.
58
     * @return collection the updated collection of metadata items.
59
     */
60
    public static function get_metadata(collection $items): collection {
61
        $items->add_database_table(
62
            'choice_answers',
63
            [
64
                'choiceid' => 'privacy:metadata:choice_answers:choiceid',
65
                'optionid' => 'privacy:metadata:choice_answers:optionid',
66
                'userid' => 'privacy:metadata:choice_answers:userid',
67
                'timemodified' => 'privacy:metadata:choice_answers:timemodified',
68
            ],
69
            'privacy:metadata:choice_answers'
70
        );
71
 
72
        return $items;
73
    }
74
 
75
    /**
76
     * Get the list of contexts that contain user information for the specified user.
77
     *
78
     * @param int $userid the userid.
79
     * @return contextlist the list of contexts containing user info for the user.
80
     */
81
    public static function get_contexts_for_userid(int $userid): contextlist {
82
        // Fetch all choice answers.
83
        $sql = "SELECT c.id
84
                  FROM {context} c
85
            INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
86
            INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
87
            INNER JOIN {choice} ch ON ch.id = cm.instance
88
            INNER JOIN {choice_options} co ON co.choiceid = ch.id
89
            INNER JOIN {choice_answers} ca ON ca.optionid = co.id AND ca.choiceid = ch.id
90
                 WHERE ca.userid = :userid";
91
 
92
        $params = [
93
            'modname'       => 'choice',
94
            'contextlevel'  => CONTEXT_MODULE,
95
            'userid'        => $userid,
96
        ];
97
        $contextlist = new contextlist();
98
        $contextlist->add_from_sql($sql, $params);
99
 
100
        return $contextlist;
101
    }
102
 
103
    /**
104
     * Get the list of users who have data within a context.
105
     *
106
     * @param   userlist    $userlist   The userlist containing the list of users who have data in this context/plugin combination.
107
     */
108
    public static function get_users_in_context(userlist $userlist) {
109
        $context = $userlist->get_context();
110
 
111
        if (!$context instanceof \context_module) {
112
            return;
113
        }
114
 
115
        // Fetch all choice answers.
116
        $sql = "SELECT ca.userid
117
                  FROM {course_modules} cm
118
                  JOIN {modules} m ON m.id = cm.module AND m.name = :modname
119
                  JOIN {choice} ch ON ch.id = cm.instance
120
                  JOIN {choice_options} co ON co.choiceid = ch.id
121
                  JOIN {choice_answers} ca ON ca.optionid = co.id AND ca.choiceid = ch.id
122
                 WHERE cm.id = :cmid";
123
 
124
        $params = [
125
            'cmid'      => $context->instanceid,
126
            'modname'   => 'choice',
127
        ];
128
 
129
        $userlist->add_from_sql('userid', $sql, $params);
130
    }
131
 
132
    /**
133
     * Export personal data for the given approved_contextlist. User and context information is contained within the contextlist.
134
     *
135
     * @param approved_contextlist $contextlist a list of contexts approved for export.
136
     */
137
    public static function export_user_data(approved_contextlist $contextlist) {
138
        global $DB;
139
 
140
        if (empty($contextlist->count())) {
141
            return;
142
        }
143
 
144
        $user = $contextlist->get_user();
145
 
146
        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
147
 
148
        $sql = "SELECT cm.id AS cmid,
149
                       co.text as answer,
150
                       ca.timemodified
151
                  FROM {context} c
152
            INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
153
            INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
154
            INNER JOIN {choice} ch ON ch.id = cm.instance
155
            INNER JOIN {choice_options} co ON co.choiceid = ch.id
156
            INNER JOIN {choice_answers} ca ON ca.optionid = co.id AND ca.choiceid = ch.id
157
                 WHERE c.id {$contextsql}
158
                       AND ca.userid = :userid
159
              ORDER BY cm.id";
160
 
161
        $params = ['modname' => 'choice', 'contextlevel' => CONTEXT_MODULE, 'userid' => $user->id] + $contextparams;
162
 
163
        // Reference to the choice activity seen in the last iteration of the loop. By comparing this with the current record, and
164
        // because we know the results are ordered, we know when we've moved to the answers for a new choice activity and therefore
165
        // when we can export the complete data for the last activity.
166
        $lastcmid = null;
167
 
168
        $choiceanswers = $DB->get_recordset_sql($sql, $params);
169
        foreach ($choiceanswers as $choiceanswer) {
170
            // If we've moved to a new choice, then write the last choice data and reinit the choice data array.
171
            if ($lastcmid != $choiceanswer->cmid) {
172
                if (!empty($choicedata)) {
173
                    $context = \context_module::instance($lastcmid);
174
                    self::export_choice_data_for_user($choicedata, $context, $user);
175
                }
176
                $choicedata = [
177
                    'answer' => [],
178
                    'timemodified' => \core_privacy\local\request\transform::datetime($choiceanswer->timemodified),
179
                ];
180
            }
181
            $choicedata['answer'][] = $choiceanswer->answer;
182
            $lastcmid = $choiceanswer->cmid;
183
        }
184
        $choiceanswers->close();
185
 
186
        // The data for the last activity won't have been written yet, so make sure to write it now!
187
        if (!empty($choicedata)) {
188
            $context = \context_module::instance($lastcmid);
189
            self::export_choice_data_for_user($choicedata, $context, $user);
190
        }
191
    }
192
 
193
    /**
194
     * Export the supplied personal data for a single choice activity, along with any generic data or area files.
195
     *
196
     * @param array $choicedata the personal data to export for the choice.
197
     * @param \context_module $context the context of the choice.
198
     * @param \stdClass $user the user record
199
     */
200
    protected static function export_choice_data_for_user(array $choicedata, \context_module $context, \stdClass $user) {
201
        // Fetch the generic module data for the choice.
202
        $contextdata = helper::get_context_data($context, $user);
203
 
204
        // Merge with choice data and write it.
205
        $contextdata = (object)array_merge((array)$contextdata, $choicedata);
206
        writer::with_context($context)->export_data([], $contextdata);
207
 
208
        // Write generic module intro files.
209
        helper::export_context_files($context, $user);
210
    }
211
 
212
    /**
213
     * Delete all data for all users in the specified context.
214
     *
215
     * @param \context $context the context to delete in.
216
     */
217
    public static function delete_data_for_all_users_in_context(\context $context) {
218
        global $DB;
219
 
220
        if (!$context instanceof \context_module) {
221
            return;
222
        }
223
 
224
        if ($cm = get_coursemodule_from_id('choice', $context->instanceid)) {
225
            $DB->delete_records('choice_answers', ['choiceid' => $cm->instance]);
226
        }
227
    }
228
 
229
    /**
230
     * Delete all user data for the specified user, in the specified contexts.
231
     *
232
     * @param approved_contextlist $contextlist a list of contexts approved for deletion.
233
     */
234
    public static function delete_data_for_user(approved_contextlist $contextlist) {
235
        global $DB;
236
 
237
        if (empty($contextlist->count())) {
238
            return;
239
        }
240
 
241
        $userid = $contextlist->get_user()->id;
242
        foreach ($contextlist->get_contexts() as $context) {
243
 
244
            if (!$context instanceof \context_module) {
245
                continue;
246
            }
247
            $instanceid = $DB->get_field('course_modules', 'instance', ['id' => $context->instanceid]);
248
            if (!$instanceid) {
249
                continue;
250
            }
251
            $DB->delete_records('choice_answers', ['choiceid' => $instanceid, 'userid' => $userid]);
252
        }
253
    }
254
 
255
    /**
256
     * Delete multiple users within a single context.
257
     *
258
     * @param   approved_userlist       $userlist The approved context and user information to delete information for.
259
     */
260
    public static function delete_data_for_users(approved_userlist $userlist) {
261
        global $DB;
262
 
263
        $context = $userlist->get_context();
264
 
265
        if (!$context instanceof \context_module) {
266
            return;
267
        }
268
 
269
        $cm = get_coursemodule_from_id('choice', $context->instanceid);
270
 
271
        if (!$cm) {
272
            // Only choice module will be handled.
273
            return;
274
        }
275
 
276
        $userids = $userlist->get_userids();
277
        list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
278
 
279
        $select = "choiceid = :choiceid AND userid $usersql";
280
        $params = ['choiceid' => $cm->instance] + $userparams;
281
        $DB->delete_records_select('choice_answers', $select, $params);
282
    }
283
}