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
 * Data provider.
19
 *
20
 * @package    mod_wiki
21
 * @copyright  2018 Marina Glancy
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace mod_wiki\privacy;
26
 
27
use core_privacy\local\metadata\collection;
28
use core_privacy\local\request\approved_contextlist;
29
use core_privacy\local\request\approved_userlist;
30
use core_privacy\local\request\contextlist;
31
use context_user;
32
use context;
33
use core_privacy\local\request\helper;
34
use core_privacy\local\request\transform;
35
use core_privacy\local\request\userlist;
36
use core_privacy\local\request\writer;
37
 
38
defined('MOODLE_INTERNAL') || die();
39
 
40
/**
41
 * Data provider class.
42
 *
43
 * @package    mod_wiki
44
 * @copyright  2018 Marina Glancy
45
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46
 */
47
class provider implements
48
    \core_privacy\local\metadata\provider,
49
    \core_privacy\local\request\core_userlist_provider,
50
    \core_privacy\local\request\plugin\provider {
51
 
52
    /**
53
     * Returns metadata.
54
     *
55
     * @param collection $collection The initialised collection to add items to.
56
     * @return collection A listing of user data stored through this system.
57
     */
58
    public static function get_metadata(collection $collection): collection {
59
 
60
        $collection->add_database_table('wiki_subwikis', [
61
            'userid' => 'privacy:metadata:wiki_subwikis:userid',
62
            'groupid' => 'privacy:metadata:wiki_subwikis:groupid',
63
        ], 'privacy:metadata:wiki_subwikis');
64
 
65
        $collection->add_database_table('wiki_pages', [
66
            'userid' => 'privacy:metadata:wiki_pages:userid',
67
            'title' => 'privacy:metadata:wiki_pages:title',
68
            'cachedcontent' => 'privacy:metadata:wiki_pages:cachedcontent',
69
            'timecreated' => 'privacy:metadata:wiki_pages:timecreated',
70
            'timemodified' => 'privacy:metadata:wiki_pages:timemodified',
71
            'timerendered' => 'privacy:metadata:wiki_pages:timerendered',
72
            'pageviews' => 'privacy:metadata:wiki_pages:pageviews',
73
            'readonly' => 'privacy:metadata:wiki_pages:readonly',
74
        ], 'privacy:metadata:wiki_pages');
75
 
76
        $collection->add_database_table('wiki_versions', [
77
            'userid' => 'privacy:metadata:wiki_versions:userid',
78
            'content' => 'privacy:metadata:wiki_versions:content',
79
            'contentformat' => 'privacy:metadata:wiki_versions:contentformat',
80
            'version' => 'privacy:metadata:wiki_versions:version',
81
            'timecreated' => 'privacy:metadata:wiki_versions:timecreated',
82
        ], 'privacy:metadata:wiki_versions');
83
 
84
        $collection->add_database_table('wiki_locks', [
85
            'userid' => 'privacy:metadata:wiki_locks:userid',
86
            'sectionname' => 'privacy:metadata:wiki_locks:sectionname',
87
            'lockedat' => 'privacy:metadata:wiki_locks:lockedat',
88
        ], 'privacy:metadata:wiki_locks');
89
 
90
        $collection->link_subsystem('core_files', 'privacy:metadata:core_files');
91
        $collection->link_subsystem('core_tag', 'privacy:metadata:core_tag');
92
        $collection->link_subsystem('core_comment', 'privacy:metadata:core_comment');
93
 
94
        // We do not report on wiki, wiki_synonyms, wiki_links because this is just context-related data.
95
 
96
        return $collection;
97
    }
98
 
99
    /**
100
     * Get the list of contexts that contain user information for the specified user.
101
     *
102
     * @param int $userid The user to search.
103
     * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
104
     */
105
    public static function get_contexts_for_userid(int $userid): contextlist {
106
        $contextlist = new contextlist();
107
 
108
        $contextlist->add_from_sql('SELECT ctx.id
109
            FROM {modules} m
110
            JOIN {course_modules} cm ON cm.module = m.id AND m.name = :modname
111
            JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevel
112
            JOIN {wiki_subwikis} s ON cm.instance = s.wikiid
113
            LEFT JOIN {wiki_pages} p ON p.subwikiid = s.id
114
            LEFT JOIN {wiki_versions} v ON v.pageid = p.id AND v.userid = :userid3
115
            LEFT JOIN {wiki_locks} l ON l.pageid = p.id AND l.userid = :userid4
116
            LEFT JOIN {comments} com ON com.itemid = p.id AND com.commentarea = :commentarea
117
                AND com.contextid = ctx.id AND com.userid = :userid5
118
            WHERE s.userid = :userid1 OR p.userid = :userid2 OR v.id IS NOT NULL OR l.id IS NOT NULL OR com.id IS NOT NULL',
119
            ['modname' => 'wiki', 'contextlevel' => CONTEXT_MODULE, 'userid1' => $userid, 'userid2' => $userid,
120
                'userid3' => $userid, 'userid4' => $userid, 'commentarea' => 'wiki_page', 'userid5' => $userid]);
121
 
122
        return $contextlist;
123
    }
124
 
125
    /**
126
     * Get the list of users who have data within a context.
127
     *
128
     * @param   userlist    $userlist   The userlist containing the list of users who have data in this context/plugin combination.
129
     */
130
    public static function get_users_in_context(userlist $userlist) {
131
        $context = $userlist->get_context();
132
 
133
        if (!is_a($context, \context_module::class)) {
134
            return;
135
        }
136
 
137
        $params = [
138
            'modname' => 'wiki',
139
            'contextlevel' => CONTEXT_MODULE,
140
            'contextid' => $context->id,
141
        ];
142
 
143
        $sql = "
144
          SELECT s.userid
145
            FROM {modules} m
146
            JOIN {course_modules} cm ON cm.module = m.id AND m.name = :modname
147
            JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevel
148
            JOIN {wiki_subwikis} s ON cm.instance = s.wikiid
149
            WHERE ctx.id = :contextid";
150
 
151
        $userlist->add_from_sql('userid', $sql, $params);
152
 
153
        $sql = "
154
          SELECT p.userid
155
            FROM {modules} m
156
            JOIN {course_modules} cm ON cm.module = m.id AND m.name = :modname
157
            JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevel
158
            JOIN {wiki_subwikis} s ON cm.instance = s.wikiid
159
            JOIN {wiki_pages} p ON p.subwikiid = s.id
160
            WHERE ctx.id = :contextid";
161
 
162
        $userlist->add_from_sql('userid', $sql, $params);
163
 
164
        $sql = "
165
          SELECT v.userid
166
            FROM {modules} m
167
            JOIN {course_modules} cm ON cm.module = m.id AND m.name = :modname
168
            JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevel
169
            JOIN {wiki_subwikis} s ON cm.instance = s.wikiid
170
            JOIN {wiki_pages} p ON p.subwikiid = s.id
171
            JOIN {wiki_versions} v ON v.pageid = p.id
172
            WHERE ctx.id = :contextid";
173
 
174
        $userlist->add_from_sql('userid', $sql, $params);
175
 
176
        $sql = "
177
          SELECT l.userid
178
            FROM {modules} m
179
            JOIN {course_modules} cm ON cm.module = m.id AND m.name = :modname
180
            JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevel
181
            JOIN {wiki_subwikis} s ON cm.instance = s.wikiid
182
            JOIN {wiki_pages} p ON p.subwikiid = s.id
183
            JOIN {wiki_locks} l ON l.pageid = p.id
184
            WHERE ctx.id = :contextid";
185
 
186
        $userlist->add_from_sql('userid', $sql, $params);
187
        \core_comment\privacy\provider::get_users_in_context_from_sql($userlist, 'com', 'mod_wiki', 'wiki_page', $context->id);
188
    }
189
 
190
    /**
191
     * Add one subwiki to the export
192
     *
193
     * Each page is added as related data because all pages in one subwiki share the same filearea
194
     *
195
     * @param stdClass $user
196
     * @param context $context
197
     * @param array $subwiki
198
     * @param string $wikimode
199
     */
200
    protected static function export_subwiki($user, context $context, $subwiki, $wikimode) {
201
        if (empty($subwiki)) {
202
            return;
203
        }
204
        $subwikiid = key($subwiki);
205
        $pages = $subwiki[$subwikiid]['pages'];
206
        unset($subwiki[$subwikiid]['pages']);
207
        writer::with_context($context)->export_data([$subwikiid], (object)$subwiki[$subwikiid]);
208
        $allfiles = $wikimode === 'individual'; // Whether to export all files or only the ones that are used.
209
 
210
        $alltexts = ''; // Store all texts that reference files to search which files are used.
211
        foreach ($pages as $page => $entry) {
212
            // Preprocess current page contents.
213
            if (!$allfiles && self::text_has_files($entry['page']['cachedcontent'])) {
214
                $alltexts .= $entry['page']['cachedcontent'];
215
            }
216
            $entry['page']['cachedcontent'] = format_text(writer::with_context($context)
217
                ->rewrite_pluginfile_urls([$subwikiid], 'mod_wiki', 'attachments',
218
                    $subwikiid, $entry['page']['cachedcontent']), FORMAT_HTML, ['context' => $context]);
219
            // Add page tags.
220
            $pagetags = \core_tag_tag::get_item_tags_array('mod_wiki', 'page', $entry['page']['id']);
221
            if ($pagetags) {
222
                $entry['page']['tags'] = $pagetags;
223
            }
224
 
225
            // Preprocess revisions.
226
            if (!empty($entry['revisions'])) {
227
                // For each revision this user has made preprocess the contents.
228
                foreach ($entry['revisions'] as &$revision) {
229
                    if ((!$allfiles && self::text_has_files($revision['content']))) {
230
                        $alltexts .= $revision['content'];
231
                    }
232
                    $revision['content'] = writer::with_context($context)
233
                        ->rewrite_pluginfile_urls([$subwikiid], 'mod_wiki', 'attachments', $subwikiid, $revision['content']);
234
                }
235
            }
236
            $comments = self::get_page_comments($user, $context, $entry['page']['id'], !array_key_exists('userid', $entry['page']));
237
            if ($comments) {
238
                $entry['page']['comments'] = $comments;
239
            }
240
            writer::with_context($context)->export_related_data([$subwikiid], $page, $entry);
241
        }
242
 
243
        if ($allfiles) {
244
            // Export all files.
245
            writer::with_context($context)->export_area_files([$subwikiid], 'mod_wiki', 'attachments', $subwikiid);
246
        } else {
247
            // Analyze which files are used in the texts.
248
            self::export_used_files($context, $subwikiid, $alltexts);
249
        }
250
    }
251
 
252
    /**
253
     * Retrieves page comments
254
     *
255
     * We can not use \core_comment\privacy\provider::export_comments() because it expects each item to have a separate
256
     * subcontext and we store wiki pages as related data to subwiki because the files are shared between pages.
257
     *
258
     * @param stdClass $user
259
     * @param \context $context
260
     * @param int $pageid
261
     * @param bool $onlyforthisuser
262
     * @return array
263
     */
264
    protected static function get_page_comments($user, \context $context, $pageid, $onlyforthisuser = true) {
265
        global $USER, $DB;
266
        $params = [
267
            'contextid' => $context->id,
268
            'commentarea' => 'wiki_page',
269
            'itemid' => $pageid
270
        ];
271
        $sql = "SELECT c.id, c.content, c.format, c.timecreated, c.userid
272
                  FROM {comments} c
273
                 WHERE c.contextid = :contextid AND
274
                       c.commentarea = :commentarea AND
275
                       c.itemid = :itemid";
276
        if ($onlyforthisuser) {
277
            $sql .= " AND c.userid = :userid";
278
            $params['userid'] = $USER->id;
279
        }
280
        $sql .= " ORDER BY c.timecreated DESC";
281
 
282
        $rs = $DB->get_recordset_sql($sql, $params);
283
        $comments = [];
284
        foreach ($rs as $record) {
285
            if ($record->userid != $user->id) {
286
                // Clean HTML in comments that were added by other users.
287
                $comment = ['content' => format_text($record->content, $record->format, ['context' => $context])];
288
            } else {
289
                // Export comments made by this user as they are stored.
290
                $comment = ['content' => $record->content, 'contentformat' => $record->format];
291
            }
292
            $comment += [
293
                'time' => transform::datetime($record->timecreated),
294
                'userid' => transform::user($record->userid),
295
            ];
296
            $comments[] = (object)$comment;
297
        }
298
        $rs->close();
299
        return $comments;
300
    }
301
 
302
    /**
303
     * Check if text has embedded files
304
     *
305
     * @param string $str
306
     * @return bool
307
     */
308
    protected static function text_has_files($str) {
309
        return strpos($str, '@@PLUGINFILE@@') !== false;
310
    }
311
 
312
    /**
313
     * Analyze which files are used in the texts and export
314
     * @param context $context
315
     * @param int $subwikiid
316
     * @param string $alltexts
317
     * @return int|void
318
     */
319
    protected static function export_used_files($context, $subwikiid, $alltexts) {
320
        if (!self::text_has_files($alltexts)) {
321
            return;
322
        }
323
        $fs = get_file_storage();
324
        $files = $fs->get_area_files($context->id, 'mod_wiki', 'attachments', $subwikiid,
325
            'filepath, filename', false);
326
        if (empty($files)) {
327
            return;
328
        }
329
        usort($files, function($file1, $file2) {
330
            return strcmp($file2->get_filepath(), $file1->get_filename());
331
        });
332
        foreach ($files as $file) {
333
            $filepath = $file->get_filepath() . $file->get_filename();
334
            $needles = ['@@PLUGINFILE@@' . s($filepath),
335
                '@@PLUGINFILE@@' . $filepath,
336
                '@@PLUGINFILE@@' . str_replace(' ', '%20', $filepath),
337
                '@@PLUGINFILE@@' . s($filepath),
338
                '@@PLUGINFILE@@' . s(str_replace(' ', '%20', $filepath))
339
            ];
340
            $needles = array_unique($needles);
341
            $newtext = str_replace($needles, '', $alltexts);
342
            if ($newtext !== $alltexts) {
343
                $alltexts = $newtext;
344
                writer::with_context($context)->export_file([$subwikiid], $file);
345
                if (!self::text_has_files($alltexts)) {
346
                    return;
347
                }
348
            }
349
        }
350
    }
351
 
352
    /**
353
     * Export all user data for the specified user, in the specified contexts.
354
     *
355
     * @param approved_contextlist $contextlist The approved contexts to export information for.
356
     */
357
    public static function export_user_data(approved_contextlist $contextlist) {
358
        global $DB;
359
 
360
        foreach ($contextlist as $context) {
361
            if ($context->contextlevel != CONTEXT_MODULE) {
362
                continue;
363
            }
364
            $user = $contextlist->get_user();
365
 
366
            $rs = $DB->get_recordset_sql('SELECT w.wikimode, s.id AS subwikiid,
367
                    s.groupid AS subwikigroupid, s.userid AS subwikiuserid,
368
                    p.id AS pageid, p.userid AS pageuserid, p.title, p.cachedcontent, p.timecreated AS pagetimecreated,
369
                    p.timemodified AS pagetimemodified, p.timerendered AS pagetimerendered, p.pageviews, p.readonly,
370
                    v.id AS versionid, v.content, v.contentformat, v.version, v.timecreated AS versiontimecreated,
371
                    l.id AS lockid, l.sectionname, l.lockedat
372
                FROM {course_modules} cm
373
                JOIN {wiki} w ON w.id = cm.instance
374
                JOIN {wiki_subwikis} s ON cm.instance = s.wikiid
375
                LEFT JOIN {wiki_pages} p ON p.subwikiid = s.id
376
                LEFT JOIN {wiki_versions} v ON v.pageid = p.id AND v.userid = :user4
377
                LEFT JOIN {wiki_locks} l ON l.pageid = p.id AND l.userid = :user5
378
                WHERE cm.id = :cmid AND (s.userid = :user1 OR p.userid = :user2 OR v.userid = :user3 OR l.userid = :user6 OR
379
                     EXISTS (SELECT 1 FROM {comments} com WHERE com.itemid = p.id AND com.commentarea = :commentarea
380
                          AND com.contextid = :ctxid AND com.userid = :user7)
381
                )
382
                ORDER BY s.id, p.id, v.id',
383
                ['cmid' => $context->instanceid,
384
                    'user1' => $user->id, 'user2' => $user->id, 'user3' => $user->id, 'user4' => $user->id,
385
                    'user5' => $user->id, 'user6' => $user->id, 'user7' => $user->id, 'commentarea' => 'wiki_page',
386
                    'ctxid' => $context->id]);
387
 
388
            if (!$rs->current()) {
389
                $rs->close();
390
                continue;
391
            }
392
 
393
            $subwiki = [];
394
            $wikimode = null;
395
            foreach ($rs as $record) {
396
                if ($wikimode === null) {
397
                    $wikimode = $record->wikimode;
398
                }
399
                if (!isset($subwiki[$record->subwikiid])) {
400
                    self::export_subwiki($user, $context, $subwiki, $wikimode);
401
                    $subwiki = [$record->subwikiid => [
402
                        'groupid' => $record->subwikigroupid,
403
                        'userid' => $record->subwikiuserid ? transform::user($record->subwikiuserid) : 0,
404
                        'pages' => []
405
                    ]];
406
                }
407
 
408
                if (!$record->pageid) {
409
                    // This is an empty individual wiki.
410
                    continue;
411
                }
412
 
413
                // Prepend page title with the page id to guarantee uniqueness.
414
                $pagetitle = format_string($record->title, true, ['context' => $context]);
415
                $page = $record->pageid . ' ' . $pagetitle;
416
                if (!isset($subwiki[$record->subwikiid]['pages'][$page])) {
417
                    // Export basic details about the page.
418
                    $subwiki[$record->subwikiid]['pages'][$page] = ['page' => [
419
                        'id' => $record->pageid,
420
                        'title' => $pagetitle,
421
                        'cachedcontent' => $record->cachedcontent,
422
                    ]];
423
                    if ($record->pageuserid == $user->id) {
424
                        // This page belongs to this user. Export all details.
425
                        $subwiki[$record->subwikiid]['pages'][$page]['page'] += [
426
                            'userid' => transform::user($user->id),
427
                            'timecreated' => transform::datetime($record->pagetimecreated),
428
                            'timemodified' => transform::datetime($record->pagetimemodified),
429
                            'timerendered' => transform::datetime($record->pagetimerendered),
430
                            'pageviews' => $record->pageviews,
431
                            'readonly' => $record->readonly,
432
                        ];
433
 
434
                        $subwiki[$record->subwikiid]['pages'][$page]['page']['userid'] = transform::user($user->id);
435
                    }
436
                }
437
 
438
                if ($record->versionid) {
439
                    $subwiki[$record->subwikiid]['pages'][$page]['revisions'][$record->versionid] = [
440
                        'content' => $record->content,
441
                        'contentformat' => $record->contentformat,
442
                        'version' => $record->version,
443
                        'timecreated' => transform::datetime($record->versiontimecreated)
444
                    ];
445
                }
446
 
447
                if ($record->lockid) {
448
                    $subwiki[$record->subwikiid]['pages'][$page]['locks'][$record->lockid] = [
449
                        'sectionname' => $record->sectionname,
450
                        'lockedat' => transform::datetime($record->lockedat),
451
                    ];
452
                }
453
 
454
            }
455
            self::export_subwiki($user, $context, $subwiki, $wikimode);
456
 
457
            if ($subwiki) {
458
                // Export wiki itself.
459
                $contextdata = helper::get_context_data($context, $user);
460
                helper::export_context_files($context, $user);
461
                writer::with_context($context)->export_data([], $contextdata);
462
            }
463
 
464
            $rs->close();
465
        }
466
    }
467
 
468
    /**
469
     * Delete all data for all users in the specified context.
470
     *
471
     * @param context $context The specific context to delete data for.
472
     */
473
    public static function delete_data_for_all_users_in_context(context $context) {
474
        global $DB;
475
 
476
        if ($context->contextlevel != CONTEXT_MODULE) {
477
            return;
478
        }
479
 
480
        $subwikis = $DB->get_fieldset_sql('SELECT s.id
481
              FROM {course_modules} cm
482
              JOIN {modules} m ON m.name = :wiki AND cm.module = m.id
483
              JOIN {wiki_subwikis} s ON s.wikiid = cm.instance
484
             WHERE cm.id = :cmid',
485
            ['cmid' => $context->instanceid, 'wiki' => 'wiki']);
486
        if (!$subwikis) {
487
            return;
488
        }
489
 
490
        $fs = get_file_storage();
491
        $fs->delete_area_files($context->id, 'mod_wiki', 'attachments');
492
 
493
        \core_tag\privacy\provider::delete_item_tags($context, 'mod_wiki', 'page');
494
 
495
        \core_comment\privacy\provider::delete_comments_for_all_users($context, 'mod_wiki', 'wiki_page');
496
 
497
        list($sql, $params) = $DB->get_in_or_equal($subwikis);
498
        $DB->delete_records_select('wiki_locks', 'pageid IN (SELECT id FROM {wiki_pages} WHERE subwikiid '.$sql.')', $params);
499
        $DB->delete_records_select('wiki_versions', 'pageid IN (SELECT id FROM {wiki_pages} WHERE subwikiid '.$sql.')', $params);
500
        $DB->delete_records_select('wiki_synonyms', 'subwikiid '.$sql, $params);
501
        $DB->delete_records_select('wiki_links', 'subwikiid '.$sql, $params);
502
        $DB->delete_records_select('wiki_pages', 'subwikiid '.$sql, $params);
503
        $DB->delete_records_select('wiki_subwikis', 'id '.$sql, $params);
504
 
505
        $DB->delete_records('tag_instance', ['contextid' => $context->id, 'component' => 'mod_wiki', 'itemtype' => 'page']);
506
    }
507
 
508
    /**
509
     * Delete all user data for the specified user, in the specified contexts.
510
     *
511
     * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
512
     */
513
    public static function delete_data_for_user(approved_contextlist $contextlist) {
514
        global $DB;
515
 
516
        $contextids = $contextlist->get_contextids();
517
 
518
        if (!$contextids) {
519
            return;
520
        }
521
 
522
        // Remove only individual subwikis. Contributions to collaborative wikis is not considered personal contents.
523
        list($ctxsql, $ctxparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
524
        $subwikis = $DB->get_records_sql_menu('SELECT s.id, ctx.id AS ctxid
525
              FROM {context} ctx
526
              JOIN {course_modules} cm ON cm.id = ctx.instanceid AND ctx.contextlevel = :contextmod
527
              JOIN {modules} m ON m.name = :wiki AND cm.module = m.id
528
              JOIN {wiki_subwikis} s ON s.wikiid = cm.instance AND s.userid = :userid
529
             WHERE ctx.id ' . $ctxsql,
530
            ['userid' => (int)$contextlist->get_user()->id, 'wiki' => 'wiki', 'contextmod' => CONTEXT_MODULE] + $ctxparams);
531
 
532
        if ($subwikis) {
533
            // We found individual subwikis that need to be deleted completely.
534
 
535
            $fs = get_file_storage();
536
            foreach ($subwikis as $subwikiid => $contextid) {
537
                $fs->delete_area_files($contextid, 'mod_wiki', 'attachments', $subwikiid);
538
                \core_comment\privacy\provider::delete_comments_for_all_users_select(context::instance_by_id($contextid),
539
                    'mod_wiki', 'wiki_page', "IN (SELECT id FROM {wiki_pages} WHERE subwikiid=:subwikiid)",
540
                    ['subwikiid' => $subwikiid]);
541
            }
542
 
543
            list($sql, $params) = $DB->get_in_or_equal(array_keys($subwikis), SQL_PARAMS_NAMED);
544
 
545
            $DB->execute("DELETE FROM {tag_instance} WHERE component=:component AND itemtype=:itemtype AND itemid IN
546
                (SELECT id FROM {wiki_pages} WHERE subwikiid $sql)",
547
                ['component' => 'mod_wiki', 'itemtype' => 'page'] + $params);
548
 
549
            $DB->delete_records_select('wiki_locks', 'pageid IN (SELECT id FROM {wiki_pages} WHERE subwikiid ' . $sql . ')',
550
                $params);
551
            $DB->delete_records_select('wiki_versions', 'pageid IN (SELECT id FROM {wiki_pages} WHERE subwikiid ' . $sql . ')',
552
                $params);
553
            $DB->delete_records_select('wiki_synonyms', 'subwikiid ' . $sql, $params);
554
            $DB->delete_records_select('wiki_links', 'subwikiid ' . $sql, $params);
555
            $DB->delete_records_select('wiki_pages', 'subwikiid ' . $sql, $params);
556
            $DB->delete_records_select('wiki_subwikis', 'id ' . $sql, $params);
557
        }
558
 
559
        // Remove comments made by this user on all other wiki pages.
560
        \core_comment\privacy\provider::delete_comments_for_user($contextlist, 'mod_wiki', 'wiki_page');
561
    }
562
 
563
    /**
564
     * Delete multiple users within a single context.
565
     *
566
     * @param   approved_userlist       $userlist The approved context and user information to delete information for.
567
     */
568
    public static function delete_data_for_users(approved_userlist $userlist) {
569
        global $DB;
570
        $context = $userlist->get_context();
571
        $userids = $userlist->get_userids();
572
 
573
        if ($context->contextlevel != CONTEXT_MODULE) {
574
            return;
575
        }
576
 
577
        // Remove only individual subwikis. Contributions to collaborative wikis is not considered personal contents.
578
        list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
579
        $params = [
580
            'wiki' => 'wiki',
581
            'contextmod' => CONTEXT_MODULE,
582
            'contextid' => $context->id,
583
        ];
584
 
585
        $params = array_merge($inparams, $params);
586
        $sql = "SELECT s.id
587
                  FROM {context} ctx
588
                  JOIN {course_modules} cm ON cm.id = ctx.instanceid AND ctx.contextlevel = :contextmod
589
                  JOIN {modules} m ON m.name = :wiki AND cm.module = m.id
590
                  JOIN {wiki_subwikis} s ON s.wikiid = cm.instance
591
                 WHERE ctx.id = :contextid
592
                   AND s.userid {$insql}";
593
 
594
        $subwikis = $DB->get_fieldset_sql($sql, $params);
595
 
596
        if ($subwikis) {
597
            // We found individual subwikis that need to be deleted completely.
598
 
599
            $fs = get_file_storage();
600
            foreach ($subwikis as $subwikiid) {
601
                $fs->delete_area_files($context->id, 'mod_wiki', 'attachments', $subwikiid);
602
                \core_comment\privacy\provider::delete_comments_for_all_users_select(context::instance_by_id($context->id),
603
                    'mod_wiki', 'wiki_page', "IN (SELECT id FROM {wiki_pages} WHERE subwikiid=:subwikiid)",
604
                    ['subwikiid' => $subwikiid]);
605
            }
606
 
607
            list($insql, $inparams) = $DB->get_in_or_equal($subwikis, SQL_PARAMS_NAMED);
608
            $params = ['component' => 'mod_wiki', 'itemtype' => 'page'];
609
            $params = array_merge($inparams, $params);
610
            $sql = "DELETE FROM {tag_instance}
611
                          WHERE component=:component
612
                            AND itemtype=:itemtype
613
                            AND itemid IN
614
                                (SELECT id
615
                                FROM {wiki_pages}
616
                                WHERE subwikiid $insql)";
617
 
618
            $DB->execute($sql, $params);
619
 
620
            $DB->delete_records_select('wiki_locks', "pageid IN (SELECT id FROM {wiki_pages} WHERE subwikiid {$insql})", $params);
621
            $DB->delete_records_select('wiki_versions', "pageid IN (SELECT id FROM {wiki_pages} WHERE subwikiid {$insql})",
622
                    $params);
623
            $DB->delete_records_select('wiki_synonyms', "subwikiid {$insql}", $params);
624
            $DB->delete_records_select('wiki_links', "subwikiid {$insql}", $params);
625
            $DB->delete_records_select('wiki_pages', "subwikiid {$insql}", $params);
626
            $DB->delete_records_select('wiki_subwikis', "id {$insql}", $params);
627
        }
628
 
629
        // Remove comments made by this user on all other wiki pages.
630
        \core_comment\privacy\provider::delete_comments_for_users($userlist, 'mod_wiki', 'wiki_page');
631
    }
632
}