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 core_tag.
19
 *
20
 * @package    core_tag
21
 * @copyright  2018 Zig Tan <zig@moodle.com>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace core_tag\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\local\request\userlist;
35
use core_privacy\local\request\approved_userlist;
36
 
37
/**
38
 * Privacy Subsystem implementation for core_tag.
39
 *
40
 * @copyright  2018 Zig Tan <zig@moodle.com>
41
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42
 */
43
class provider implements
44
        // Tags store user data.
45
        \core_privacy\local\metadata\provider,
46
 
47
        // The tag subsystem provides data to other components.
48
        \core_privacy\local\request\subsystem\plugin_provider,
49
 
50
        // This plugin is capable of determining which users have data within it.
51
        \core_privacy\local\request\core_userlist_provider,
52
 
53
        // The tag subsystem may have data that belongs to this user.
54
        \core_privacy\local\request\plugin\provider,
55
 
56
        \core_privacy\local\request\shared_userlist_provider
57
    {
58
 
59
    /**
60
     * Returns meta data about this system.
61
     *
62
     * @param   collection     $collection The initialised collection to add items to.
63
     * @return  collection     A listing of user data stored through this system.
64
     */
65
    public static function get_metadata(collection $collection): collection {
66
        // The table 'tag' contains data that a user has entered.
67
        // It is currently linked with a userid, but this field will hopefulyl go away.
68
        // Note: The userid is not necessarily 100% accurate. See MDL-61555.
69
        $collection->add_database_table('tag', [
70
                'name' => 'privacy:metadata:tag:name',
71
                'rawname' => 'privacy:metadata:tag:rawname',
72
                'description' => 'privacy:metadata:tag:description',
73
                'flag' => 'privacy:metadata:tag:flag',
74
                'timemodified' => 'privacy:metadata:tag:timemodified',
75
                'userid' => 'privacy:metadata:tag:userid',
76
            ], 'privacy:metadata:tag');
77
 
78
        // The table 'tag_instance' contains user data.
79
        // It links the user of a specific tag, to the item which is tagged.
80
        // In some cases the userid who 'owns' the tag is also stored.
81
        $collection->add_database_table('tag_instance', [
82
                'tagid' => 'privacy:metadata:taginstance:tagid',
83
                'ordering' => 'privacy:metadata:taginstance:ordering',
84
                'timecreated' => 'privacy:metadata:taginstance:timecreated',
85
                'timemodified' => 'privacy:metadata:taginstance:timemodified',
86
                'tiuserid' => 'privacy:metadata:taginstance:tiuserid',
87
            ], 'privacy:metadata:taginstance');
88
 
89
        // The table 'tag_area' does not contain any specific user data.
90
        // It links components and item types to collections and describes how they can be associated.
91
 
92
        // The table 'tag_coll' does not contain any specific user data.
93
        // It describes a list of tag collections configured by the administrator.
94
 
95
        // The table 'tag_correlation' does not contain any user data.
96
        // It is a cache for other data already stored.
97
 
98
        return $collection;
99
    }
100
 
101
    /**
102
     * Store all tags which match the specified component, itemtype, and itemid.
103
     *
104
     * In most situations you will want to specify $onlyuser as false.
105
     * This will fetch only tags where the user themselves set the tag, or where tags are a shared resource.
106
     *
107
     * If you specify $onlyuser as true, only the tags created by that user will be included.
108
     *
109
     * @param   int         $userid The user whose information is to be exported
110
     * @param   \context    $context The context to export for
111
     * @param   array       $subcontext The subcontext within the context to export this information
112
     * @param   string      $component The component to fetch data from
113
     * @param   string      $itemtype The itemtype that the data was exported in within the component
114
     * @param   int         $itemid The itemid within that tag
115
     * @param   bool        $onlyuser Whether to only export ratings that the current user has made, or all tags
116
     */
117
    public static function export_item_tags(
118
        int $userid,
119
        \context $context,
120
        array $subcontext,
121
        string $component,
122
        string $itemtype,
123
        int $itemid,
124
        bool $onlyuser = false
125
    ) {
126
        global $DB;
127
 
128
        // Ignore mdl_tag.userid here because it only reflects the user who originally created the tag.
129
        $sql = "SELECT
130
                    t.rawname
131
                  FROM {tag} t
132
            INNER JOIN {tag_instance} ti ON ti.tagid = t.id
133
                 WHERE ti.component = :component
134
                   AND ti.itemtype = :itemtype
135
                   AND ti.itemid = :itemid
136
                   ";
137
 
138
        if ($onlyuser) {
139
            $sql .= "AND ti.tiuserid = :userid";
140
        } else {
141
            $sql .= "AND (ti.tiuserid = 0 OR ti.tiuserid = :userid)";
142
        }
143
 
144
        $params = [
145
            'component' => $component,
146
            'itemtype' => $itemtype,
147
            'itemid' => $itemid,
148
            'userid' => $userid,
149
        ];
150
 
151
        if ($tags = $DB->get_fieldset_sql($sql, $params)) {
152
            $writer = \core_privacy\local\request\writer::with_context($context)
153
                ->export_related_data($subcontext, 'tags', $tags);
154
        }
155
    }
156
 
157
    /**
158
     * Deletes all tag instances for given context, component, itemtype, itemid
159
     *
160
     * In most situations you will want to specify $userid as null. Per-user tag instances
161
     * are possible in Tags API, however there are no components or standard plugins that actually use them.
162
     *
163
     * @param   \context    $context The context to export for
164
     * @param   string      $component Tagarea component
165
     * @param   string      $itemtype Tagarea item type
166
     * @param   int         $itemid The itemid within that component and itemtype (optional)
167
     * @param   int         $userid Only delete tag instances made by this user, per-user tags must be enabled for the tagarea
168
     */
169
    public static function delete_item_tags(\context $context, $component, $itemtype,
170
            $itemid = null, $userid = null) {
171
        global $DB;
172
        $params = ['contextid' => $context->id, 'component' => $component, 'itemtype' => $itemtype];
173
        if ($itemid) {
174
            $params['itemid'] = $itemid;
175
        }
176
        if ($userid) {
177
            $params['tiuserid'] = $userid;
178
        }
179
        $DB->delete_records('tag_instance', $params);
180
    }
181
 
182
    /**
183
     * Deletes all tag instances for given context, component, itemtype using subquery for itemids
184
     *
185
     * In most situations you will want to specify $userid as null. Per-user tag instances
186
     * are possible in Tags API, however there are no components or standard plugins that actually use them.
187
     *
188
     * @param   \context    $context The context to export for
189
     * @param   string      $component Tagarea component
190
     * @param   string      $itemtype Tagarea item type
191
     * @param   string      $itemidstest an SQL fragment that the itemid must match. Used
192
     *      in the query like WHERE itemid $itemidstest. Must use named parameters,
193
     *      and may not use named parameters called contextid, component or itemtype.
194
     * @param array $params any query params used by $itemidstest.
195
     */
196
    public static function delete_item_tags_select(\context $context, $component, $itemtype,
197
                                            $itemidstest, $params = []) {
198
        global $DB;
199
        $params += ['contextid' => $context->id, 'component' => $component, 'itemtype' => $itemtype];
200
        $DB->delete_records_select('tag_instance',
201
            'contextid = :contextid AND component = :component AND itemtype = :itemtype AND itemid ' . $itemidstest,
202
            $params);
203
    }
204
 
205
    /**
206
     * Get the list of contexts that contain user information for the specified user.
207
     *
208
     * @param   int         $userid     The user to search.
209
     * @return  contextlist   $contextlist  The contextlist containing the list of contexts used in this plugin.
210
     */
211
    public static function get_contexts_for_userid(int $userid): contextlist {
212
        $contextlist = new contextlist();
213
        $contextlist->add_from_sql("SELECT c.id
214
                  FROM {context} c
215
                  JOIN {tag} t ON t.userid = :userid
216
                 WHERE contextlevel = :contextlevel",
217
            ['userid' => $userid, 'contextlevel' => CONTEXT_SYSTEM]);
218
        return $contextlist;
219
    }
220
 
221
    /**
222
     * Get the list of users within a specific context.
223
     *
224
     * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
225
     */
226
    public static function get_users_in_context(userlist $userlist) {
227
        $context = $userlist->get_context();
228
 
229
        if (!$context instanceof \context_system) {
230
            return;
231
        }
232
 
233
        $sql = "SELECT userid
234
                  FROM {tag}";
235
 
236
        $userlist->add_from_sql('userid', $sql, []);
237
    }
238
 
239
    /**
240
     * Export all user data for the specified user, in the specified contexts.
241
     *
242
     * @param   approved_contextlist    $contextlist    The approved contexts to export information for.
243
     */
244
    public static function export_user_data(approved_contextlist $contextlist) {
245
        global $DB;
246
        $context = \context_system::instance();
247
        if (!$contextlist->count() || !in_array($context->id, $contextlist->get_contextids())) {
248
            return;
249
        }
250
 
251
        $user = $contextlist->get_user();
252
        $sql = "SELECT id, userid, tagcollid, name, rawname, isstandard, description, descriptionformat, flag, timemodified
253
            FROM {tag} WHERE userid = ?";
254
        $rs = $DB->get_recordset_sql($sql, [$user->id]);
255
        foreach ($rs as $record) {
256
            $subcontext = [get_string('tags', 'tag'), $record->id];
257
            $tag = (object)[
258
                'id' => $record->id,
259
                'userid' => transform::user($record->userid),
260
                'name' => $record->name,
261
                'rawname' => $record->rawname,
262
                'isstandard' => transform::yesno($record->isstandard),
263
                'description' => writer::with_context($context)->rewrite_pluginfile_urls($subcontext,
264
                    'tag', 'description', $record->id, strval($record->description)),
265
                'descriptionformat' => $record->descriptionformat,
266
                'flag' => $record->flag,
267
                'timemodified' => transform::datetime($record->timemodified),
268
 
269
            ];
270
            writer::with_context($context)->export_data($subcontext, $tag);
271
            writer::with_context($context)->export_area_files($subcontext, 'tag', 'description', $record->id);
272
        }
273
        $rs->close();
274
    }
275
 
276
    /**
277
     * Delete all data for all users in the specified context.
278
     *
279
     * We do not delete tag instances in this method - this should be done by the components that define tagareas.
280
     * We only delete tags themselves in case of system context.
281
     *
282
     * @param context $context   The specific context to delete data for.
283
     */
284
    public static function delete_data_for_all_users_in_context(\context $context) {
285
        global $DB;
286
        // Tags can only be defined in system context.
287
        if ($context->id == \context_system::instance()->id) {
288
            $DB->delete_records('tag_instance');
289
            $DB->delete_records('tag', []);
290
        }
291
    }
292
 
293
    /**
294
     * Delete multiple users within a single context.
295
     *
296
     * @param approved_userlist $userlist The approved context and user information to delete information for.
297
     */
298
    public static function delete_data_for_users(approved_userlist $userlist) {
299
        global $DB;
300
 
301
        $context = $userlist->get_context();
302
 
303
        if ($context instanceof \context_system) {
304
            // Do not delete tags themselves in case they are used by somebody else.
305
            // If the user is the only one using the tag, it will be automatically deleted anyway during the
306
            // next cron cleanup.
307
            list($usersql, $userparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
308
            $DB->set_field_select('tag', 'userid', 0, "userid {$usersql}", $userparams);
309
        }
310
    }
311
 
312
    /**
313
     * Delete all user data for the specified user, in the specified contexts.
314
     *
315
     * @param   approved_contextlist    $contextlist    The approved contexts and user information to delete information for.
316
     */
317
    public static function delete_data_for_user(approved_contextlist $contextlist) {
318
        global $DB;
319
        $context = \context_system::instance();
320
        if (!$contextlist->count() || !in_array($context->id, $contextlist->get_contextids())) {
321
            return;
322
        }
323
 
324
        // Do not delete tags themselves in case they are used by somebody else.
325
        // If the user is the only one using the tag, it will be automatically deleted anyway during the next cron cleanup.
326
        $DB->set_field_select('tag', 'userid', 0, 'userid = ?', [$contextlist->get_user()->id]);
327
    }
328
}