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_group.
19
 *
20
 * @package    core_group
21
 * @category   privacy
22
 * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 */
25
 
26
namespace core_group\privacy;
27
 
28
defined('MOODLE_INTERNAL') || die();
29
 
30
use core_privacy\local\metadata\collection;
31
use core_privacy\local\request\approved_contextlist;
32
use core_privacy\local\request\approved_userlist;
33
use core_privacy\local\request\contextlist;
34
use core_privacy\local\request\transform;
35
use core_privacy\local\request\userlist;
36
 
37
/**
38
 * Privacy Subsystem implementation for core_group.
39
 *
40
 * @copyright  2018 Shamim Rezaie <shamim@moodle.com>
41
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42
 */
43
class provider implements
44
        // Groups store user data.
45
        \core_privacy\local\metadata\provider,
46
 
47
        // The group subsystem contains user's group memberships.
48
        \core_privacy\local\request\subsystem\provider,
49
 
50
        // The group subsystem can provide information to other plugins.
51
        \core_privacy\local\request\subsystem\plugin_provider,
52
 
53
        // This plugin is capable of determining which users have data within it.
54
        \core_privacy\local\request\core_userlist_provider,
55
        \core_privacy\local\request\shared_userlist_provider
56
    {
57
 
58
    /**
59
     * Returns meta data about this system.
60
     *
61
     * @param   collection $collection The initialised collection to add items to.
62
     * @return  collection A listing of user data stored through this system.
63
     */
64
    public static function get_metadata(collection $collection): collection {
65
        $collection->add_database_table('groups_members', [
66
            'groupid' => 'privacy:metadata:groups:groupid',
67
            'userid' => 'privacy:metadata:groups:userid',
68
            'timeadded' => 'privacy:metadata:groups:timeadded',
69
        ], 'privacy:metadata:groups');
70
 
71
        $collection->link_subsystem('core_message', 'privacy:metadata:core_message');
72
 
73
        return $collection;
74
    }
75
 
76
    /**
77
     * Writes user data to the writer for the user to download.
78
     *
79
     * @param \context  $context    The context to export data for.
80
     * @param string    $component  The component that is calling this function. Empty string means no component.
81
     * @param array     $subcontext The sub-context in which to export this data.
82
     * @param int       $itemid     Optional itemid associated with component.
83
     */
84
    public static function export_groups(\context $context, string $component, array $subcontext = [], int $itemid = 0) {
85
        global $DB, $USER;
86
 
87
        if (!$context instanceof \context_course) {
88
            return;
89
        }
90
 
91
        $subcontext[] = get_string('groups', 'core_group');
92
 
93
        $sql = "SELECT gm.id, gm.timeadded, gm.userid, g.name, gm.groupid
94
                  FROM {groups_members} gm
95
                  JOIN {groups} g ON gm.groupid = g.id
96
                 WHERE g.courseid = :courseid
97
                       AND gm.component = :component
98
                       AND gm.userid = :userid";
99
        $params = [
100
            'courseid'  => $context->instanceid,
101
            'component' => $component,
102
            'userid'    => $USER->id
103
        ];
104
 
105
        if ($itemid) {
106
            $sql .= ' AND gm.itemid = :itemid';
107
            $params['itemid'] = $itemid;
108
        }
109
 
110
        $groups = $DB->get_records_sql($sql, $params);
111
 
112
        $groupstoexport = array_map(function($group) {
113
            return (object) [
114
                'name' => format_string($group->name),
115
                'timeadded' => transform::datetime($group->timeadded),
116
            ];
117
        }, $groups);
118
 
119
        if (!empty($groups)) {
120
            \core_privacy\local\request\writer::with_context($context)
121
                    ->export_data($subcontext, (object) [
122
                        'groups' => $groupstoexport,
123
                    ]);
124
 
125
            foreach ($groups as $group) {
126
                // Export associated conversations to this group.
127
                \core_message\privacy\provider::export_conversations($USER->id, 'core_group', 'groups',
128
                    $context, [], $group->groupid);
129
            }
130
        }
131
    }
132
 
133
    /**
134
     * Deletes all group memberships for a specified context and component.
135
     *
136
     * @param \context  $context    Details about which context to delete group memberships for.
137
     * @param string    $component  Component to delete. Empty string means no component (manual group memberships).
138
     * @param int       $itemid     Optional itemid associated with component.
139
     */
140
    public static function delete_groups_for_all_users(\context $context, string $component, int $itemid = 0) {
141
        global $DB;
142
 
143
        if (!$context instanceof \context_course) {
144
            return;
145
        }
146
 
147
        if (!$DB->record_exists('groups', ['courseid' => $context->instanceid])) {
148
            return;
149
        }
150
 
151
        $select = "component = :component AND groupid IN (SELECT g.id FROM {groups} g WHERE courseid = :courseid)";
152
        $params = ['component' => $component, 'courseid' => $context->instanceid];
153
 
154
        if ($itemid) {
155
            $select .= ' AND itemid = :itemid';
156
            $params['itemid'] = $itemid;
157
        }
158
 
159
        // Delete the group conversations.
160
        $groups = $DB->get_records_select('groups_members', $select, $params);
161
        foreach ($groups as $group) {
162
            \core_message\privacy\provider::delete_conversations_for_all_users($context, 'core_group', 'groups', $group->groupid);
163
        }
164
 
165
        // Remove members from the group.
166
        $DB->delete_records_select('groups_members', $select, $params);
167
 
168
        // Purge the group and grouping cache for users.
169
        \cache_helper::purge_by_definition('core', 'user_group_groupings');
170
    }
171
 
172
    /**
173
     * Deletes all records for a user from a list of approved contexts.
174
     *
175
     * @param approved_contextlist  $contextlist    Contains the user ID and a list of contexts to be deleted from.
176
     * @param string                $component      Component to delete from. Empty string means no component (manual memberships).
177
     * @param int                   $itemid         Optional itemid associated with component.
178
     */
179
    public static function delete_groups_for_user(approved_contextlist $contextlist, string $component, int $itemid = 0) {
180
        global $DB;
181
 
182
        $userid = $contextlist->get_user()->id;
183
 
184
        $contextids = $contextlist->get_contextids();
185
 
186
        if (!$contextids) {
187
            return;
188
        }
189
 
190
        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
191
        $contextparams += ['contextcourse' => CONTEXT_COURSE];
192
        $groupselect = "SELECT g.id
193
                          FROM {groups} g
194
                          JOIN {context} ctx ON g.courseid = ctx.instanceid AND ctx.contextlevel = :contextcourse
195
                         WHERE ctx.id $contextsql";
196
 
197
        if (!$DB->record_exists_sql($groupselect, $contextparams)) {
198
            return;
199
        }
200
 
201
        $select = "userid = :userid AND component = :component AND groupid IN ({$groupselect})";
202
        $params = ['userid' => $userid, 'component' => $component] + $contextparams;
203
 
204
        if ($itemid) {
205
            $select .= ' AND itemid = :itemid';
206
            $params['itemid'] = $itemid;
207
        }
208
 
209
        // Delete the group conversations.
210
        $groups = $DB->get_records_select('groups_members', $select, $params);
211
        foreach ($groups as $group) {
212
            \core_message\privacy\provider::delete_conversations_for_user($contextlist, 'core_group', 'groups', $group->groupid);
213
        }
214
 
215
        // Remove members from the group.
216
        $DB->delete_records_select('groups_members', $select, $params);
217
 
218
        // Invalidate the group and grouping cache for the user.
219
        \cache_helper::invalidate_by_definition('core', 'user_group_groupings', array(), array($userid));
220
    }
221
 
222
    /**
223
     * Add the list of users who are members of some groups in the specified constraints.
224
     *
225
     * @param   userlist    $userlist   The userlist to add the users to.
226
     * @param   string      $component  The component to check.
227
     * @param   int         $itemid     Optional itemid associated with component.
228
     */
229
    public static function get_group_members_in_context(userlist $userlist, string $component, int $itemid = 0) {
230
        $context = $userlist->get_context();
231
 
232
        if (!$context instanceof \context_course) {
233
            return;
234
        }
235
 
236
        // Group members in the given context.
237
        $sql = "SELECT gm.userid
238
                  FROM {groups_members} gm
239
                  JOIN {groups} g ON gm.groupid = g.id
240
                 WHERE g.courseid = :courseid AND gm.component = :component";
241
        $params = [
242
            'courseid'      => $context->instanceid,
243
            'component'     => $component
244
        ];
245
 
246
        if ($itemid) {
247
            $sql .= ' AND gm.itemid = :itemid';
248
            $params['itemid'] = $itemid;
249
        }
250
 
251
        $userlist->add_from_sql('userid', $sql, $params);
252
 
253
        // Get the users with some group conversation in this context.
254
        \core_message\privacy\provider::add_conversations_in_context($userlist, 'core_group', 'groups', $itemid);
255
    }
256
 
257
    /**
258
     * Deletes all records for multiple users within a single context.
259
     *
260
     * @param approved_userlist $userlist   The approved context and user information to delete information for.
261
     * @param string            $component  Component to delete from. Empty string means no component (manual memberships).
262
     * @param int               $itemid     Optional itemid associated with component.
263
     */
264
    public static function delete_groups_for_users(approved_userlist $userlist, string $component, int $itemid = 0) {
265
        global $DB;
266
 
267
        $context = $userlist->get_context();
268
        $userids = $userlist->get_userids();
269
 
270
        if (!$context instanceof \context_course) {
271
            return;
272
        }
273
 
274
        list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
275
 
276
        $groupselect = "SELECT id FROM {groups} WHERE courseid = :courseid";
277
        $groupparams = ['courseid' => $context->instanceid];
278
 
279
        $select = "component = :component AND userid {$usersql} AND groupid IN ({$groupselect})";
280
        $params = ['component' => $component] + $groupparams + $userparams;
281
 
282
        if ($itemid) {
283
            $select .= ' AND itemid = :itemid';
284
            $params['itemid'] = $itemid;
285
        }
286
 
287
        // Delete the group conversations for these users.
288
        $groups = $DB->get_records_select('groups_members', $select, $params);
289
        foreach ($groups as $group) {
290
            \core_message\privacy\provider::delete_conversations_for_users($userlist, 'core_group', 'groups', $group->groupid);
291
        }
292
 
293
        $DB->delete_records_select('groups_members', $select, $params);
294
 
295
        // Invalidate the group and grouping cache for the user.
296
        \cache_helper::invalidate_by_definition('core', 'user_group_groupings', array(), $userids);
297
    }
298
 
299
    /**
300
     * Get the list of contexts that contain group membership for the specified user.
301
     *
302
     * @param   int     $userid     The user to search.
303
     * @param   string  $component  The component to check.
304
     * @param   int     $itemid     Optional itemid associated with component.
305
     * @return  contextlist         The contextlist containing the list of contexts.
306
     */
307
    public static function get_contexts_for_group_member(int $userid, string $component, int $itemid = 0) {
308
        $contextlist = new contextlist();
309
 
310
        $sql = "SELECT ctx.id
311
                  FROM {groups_members} gm
312
                  JOIN {groups} g ON gm.groupid = g.id
313
                  JOIN {context} ctx ON g.courseid = ctx.instanceid AND ctx.contextlevel = :contextcourse
314
                 WHERE gm.userid = :userid AND gm.component = :component";
315
 
316
        $params = [
317
            'contextcourse' => CONTEXT_COURSE,
318
            'userid'        => $userid,
319
            'component'     => $component
320
        ];
321
 
322
        if ($itemid) {
323
            $sql .= ' AND gm.itemid = :itemid';
324
            $params['itemid'] = $itemid;
325
        }
326
 
327
        $contextlist->add_from_sql($sql, $params);
328
 
329
        // Get the contexts where the userid has group conversations.
330
        \core_message\privacy\provider::add_contexts_for_conversations($contextlist, $userid, 'core_group', 'groups', $itemid);
331
 
332
        return $contextlist;
333
    }
334
 
335
    /**
336
     * Get the list of users who have data within a context.
337
     *
338
     * @param   int $userid The user to search.
339
     * @return  contextlist The contextlist containing the list of contexts used in this plugin.
340
     */
341
    public static function get_contexts_for_userid(int $userid): contextlist {
342
        return static::get_contexts_for_group_member($userid, '');
343
    }
344
 
345
    /**
346
     * Get the list of users who have data within a context.
347
     *
348
     * @param   userlist    $userlist   The userlist containing the list of users who have data in this context/plugin combination.
349
     */
350
    public static function get_users_in_context(userlist $userlist) {
351
        $context = $userlist->get_context();
352
 
353
        if (!$context instanceof \context_course) {
354
            return;
355
        }
356
 
357
        static::get_group_members_in_context($userlist, '');
358
    }
359
 
360
    /**
361
     * Export all user data for the specified user, in the specified contexts.
362
     *
363
     * @param approved_contextlist $contextlist The approved contexts to export information for.
364
     */
365
    public static function export_user_data(approved_contextlist $contextlist) {
366
        $contexts = $contextlist->get_contexts();
367
 
368
        foreach ($contexts as $context) {
369
            static::export_groups($context, '');
370
        }
371
    }
372
 
373
    /**
374
     * Delete all data for all users in the specified context.
375
     *
376
     * @param context $context The specific context to delete data for.
377
     */
378
    public static function delete_data_for_all_users_in_context(\context $context) {
379
        static::delete_groups_for_all_users($context, '');
380
    }
381
 
382
    /**
383
     * Delete all user data for the specified user, in the specified contexts.
384
     *
385
     * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
386
     */
387
    public static function delete_data_for_user(approved_contextlist $contextlist) {
388
        static::delete_groups_for_user($contextlist, '');
389
    }
390
 
391
    /**
392
     * Delete multiple users within a single context.
393
     *
394
     * @param   approved_userlist   $userlist   The approved context and user information to delete information for.
395
     */
396
    public static function delete_data_for_users(approved_userlist $userlist) {
397
        static::delete_groups_for_users($userlist, '');
398
    }
399
 
400
}