Merge branch 'MDL-64851-master' of https://github.com/s-cenni/MDL-64851
[moodle.git] / blog / tests / privacy_test.php
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/>.
17 /**
18  * Data provider tests.
19  *
20  * @package    core_blog
21  * @category   test
22  * @copyright  2018 Frédéric Massart
23  * @author     Frédéric Massart <fred@branchup.tech>
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
30 use core_privacy\tests\provider_testcase;
31 use core_privacy\local\request\approved_contextlist;
32 use core_privacy\local\request\transform;
33 use core_privacy\local\request\writer;
34 use core_blog\privacy\provider;
36 require_once($CFG->dirroot . '/blog/locallib.php');
37 require_once($CFG->dirroot . '/comment/lib.php');
39 /**
40  * Data provider testcase class.
41  *
42  * @package    core_blog
43  * @category   test
44  * @copyright  2018 Frédéric Massart
45  * @author     Frédéric Massart <fred@branchup.tech>
46  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
47  */
48 class core_blog_privacy_testcase extends provider_testcase {
50     public function setUp() {
51         $this->resetAfterTest();
52     }
54     public function test_get_contexts_for_userid() {
55         $dg = $this->getDataGenerator();
56         $c1 = $dg->create_course();
57         $c2 = $dg->create_course();
58         $c3 = $dg->create_course();
59         $cm1a = $dg->create_module('page', ['course' => $c1]);
60         $cm1b = $dg->create_module('page', ['course' => $c1]);
61         $cm2a = $dg->create_module('page', ['course' => $c2]);
62         $u1 = $dg->create_user();
63         $u2 = $dg->create_user();
64         $u1ctx = context_user::instance($u1->id);
66         // Blog share a table with notes, so throw data in there and make sure it doesn't get reported.
67         $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c3->id]);
69         $this->assertEmpty(provider::get_contexts_for_userid($u1->id)->get_contextids());
70         $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids());
72         // Gradually create blog posts for user 1. First system one.
73         $this->create_post(['userid' => $u1->id]);
74         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
75         $this->assertCount(1, $contextids);
76         $this->assertEquals($u1ctx->id, $contextids[0]);
77         $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids());
79         // Create a blog post associated with c1.
80         $post = $this->create_post(['userid' => $u1->id, 'courseid' => $c1->id]);
81         $entry = new blog_entry($post->id);
82         $entry->add_association(context_course::instance($c1->id)->id);
83         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
84         $this->assertCount(2, $contextids);
85         $this->assertTrue(in_array($u1ctx->id, $contextids));
86         $this->assertTrue(in_array(context_course::instance($c1->id)->id, $contextids));
87         $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids());
89         // Create a blog post associated with cm2a.
90         $post = $this->create_post(['userid' => $u1->id, 'courseid' => $c2->id]);
91         $entry = new blog_entry($post->id);
92         $entry->add_association(context_module::instance($cm2a->cmid)->id);
93         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
94         $this->assertCount(3, $contextids);
95         $this->assertTrue(in_array($u1ctx->id, $contextids));
96         $this->assertTrue(in_array(context_course::instance($c1->id)->id, $contextids));
97         $this->assertTrue(in_array(context_module::instance($cm2a->cmid)->id, $contextids));
98         $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids());
100         // User 2 comments on u1's post.
101         $comment = $this->get_comment_object($u1ctx, $post->id);
102         $this->setUser($u2);
103         $comment->add('Hello, it\'s me!');
104         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
105         $this->assertCount(3, $contextids);
106         $this->assertTrue(in_array($u1ctx->id, $contextids));
107         $this->assertTrue(in_array(context_course::instance($c1->id)->id, $contextids));
108         $this->assertTrue(in_array(context_module::instance($cm2a->cmid)->id, $contextids));
109         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
110         $this->assertCount(1, $contextids);
111         $this->assertTrue(in_array($u1ctx->id, $contextids));
112     }
114     public function test_get_contexts_for_userid_with_one_associated_post_only() {
115         $dg = $this->getDataGenerator();
116         $c1 = $dg->create_course();
117         $u1 = $dg->create_user();
118         $u1ctx = context_user::instance($u1->id);
120         $this->assertEmpty(provider::get_contexts_for_userid($u1->id)->get_contextids());
122         // Create a blog post associated with c1. It should always return both the course and user context.
123         $post = $this->create_post(['userid' => $u1->id, 'courseid' => $c1->id]);
124         $entry = new blog_entry($post->id);
125         $entry->add_association(context_course::instance($c1->id)->id);
126         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
127         $this->assertCount(2, $contextids);
128         $this->assertTrue(in_array($u1ctx->id, $contextids));
129         $this->assertTrue(in_array(context_course::instance($c1->id)->id, $contextids));
130     }
132     /**
133      * Test that user IDs are returned for a specificed course or module context.
134      */
135     public function test_get_users_in_context_course_and_module() {
136         $user1 = $this->getDataGenerator()->create_user();
137         $user2 = $this->getDataGenerator()->create_user();
138         $course = $this->getDataGenerator()->create_course();
139         $c1ctx = context_course::instance($course->id);
141         $post = $this->create_post(['userid' => $user1->id, 'courseid' => $course->id]);
142         $entry = new blog_entry($post->id);
143         $entry->add_association($c1ctx->id);
145         // Add a comment from user 2.
146         $comment = $this->get_comment_object(context_user::instance($user1->id), $entry->id);
147         $this->setUser($user2);
148         $comment->add('Nice blog post');
150         $userlist = new \core_privacy\local\request\userlist($c1ctx, 'core_blog');
151         provider::get_users_in_context($userlist);
152         $userids = $userlist->get_userids();
153         $this->assertCount(2, $userids);
155         // Add an association for a module.
156         $cm1a = $this->getDataGenerator()->create_module('page', ['course' => $course]);
157         $cm1ctx = context_module::instance($cm1a->cmid);
159         $post2 = $this->create_post(['userid' => $user2->id, 'courseid' => $course->id]);
160         $entry2 = new blog_entry($post2->id);
161         $entry2->add_association($cm1ctx->id);
163         $userlist = new \core_privacy\local\request\userlist($cm1ctx, 'core_blog');
164         provider::get_users_in_context($userlist);
165         $userids = $userlist->get_userids();
166         $this->assertCount(1, $userids);
167     }
169     /**
170      * Test that user IDs are returned for a specificed user context.
171      */
172     public function test_get_users_in_context_user_context() {
173         $user1 = $this->getDataGenerator()->create_user();
174         $user2 = $this->getDataGenerator()->create_user();
175         $u1ctx = context_user::instance($user1->id);
177         $post = $this->create_post(['userid' => $user1->id]);
178         $entry = new blog_entry($post->id);
180         // Add a comment from user 2.
181         $comment = $this->get_comment_object($u1ctx, $entry->id);
182         $this->setUser($user2);
183         $comment->add('Another nice blog post');
185         $userlist = new \core_privacy\local\request\userlist($u1ctx, 'core_blog');
186         provider::get_users_in_context($userlist);
187         $userids = $userlist->get_userids();
188         $this->assertCount(2, $userids);
189     }
191     /**
192      * Test that user IDs are returned for a specificed user context for an external blog.
193      */
194     public function test_get_users_in_context_external_blog() {
195         $user1 = $this->getDataGenerator()->create_user();
196         $u1ctx = context_user::instance($user1->id);
197         $extu1 = $this->create_external_blog(['userid' => $user1->id]);
199         $userlist = new \core_privacy\local\request\userlist($u1ctx, 'core_blog');
200         provider::get_users_in_context($userlist);
201         $userids = $userlist->get_userids();
202         $this->assertCount(1, $userids);
203     }
205     public function test_delete_data_for_user() {
206         global $DB;
208         $dg = $this->getDataGenerator();
209         $c1 = $dg->create_course();
210         $c2 = $dg->create_course();
211         $cm1a = $dg->create_module('page', ['course' => $c1]);
212         $cm1b = $dg->create_module('page', ['course' => $c1]);
213         $cm2a = $dg->create_module('page', ['course' => $c2]);
214         $u1 = $dg->create_user();
215         $u2 = $dg->create_user();
216         $u3 = $dg->create_user();
218         $c1ctx = context_course::instance($c1->id);
219         $c2ctx = context_course::instance($c2->id);
220         $cm1actx = context_module::instance($cm1a->cmid);
221         $cm1bctx = context_module::instance($cm1b->cmid);
222         $cm2actx = context_module::instance($cm2a->cmid);
223         $u1ctx = context_user::instance($u1->id);
224         $u2ctx = context_user::instance($u2->id);
226         // Blog share a table with notes, so throw data in there and make sure it doesn't get deleted.
227         $this->assertFalse($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
228         $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c1->id]);
229         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
231         // Create two external blogs.
232         $extu1 = $this->create_external_blog(['userid' => $u1->id]);
233         $extu2 = $this->create_external_blog(['userid' => $u2->id]);
235         // Create a set of posts.
236         $entry = new blog_entry($this->create_post(['userid' => $u1->id])->id);
237         $commentedon = $entry;
238         $entry = new blog_entry($this->create_post(['userid' => $u2->id])->id);
240         // Two course associations for u1.
241         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
242         $entry->add_association($c1ctx->id);
243         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
244         $entry->add_association($c1ctx->id);
246         // Two module associations with cm1a, and 1 with cm1b for u1.
247         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
248         $entry->add_association($cm1actx->id);
249         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
250         $entry->add_association($cm1actx->id);
251         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
252         $entry->add_association($cm1bctx->id);
254         // One association for u2 in c1, cm1a and cm2a.
255         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
256         $entry->add_association($c1ctx->id);
257         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
258         $entry->add_association($cm1actx->id);
259         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c2->id])->id);
260         $entry->add_association($cm2actx->id);
262         // One association for u1 in c2 and cm2a.
263         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id);
264         $entry->add_association($c2ctx->id);
265         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id);
266         $entry->add_association($cm2actx->id);
268         // Add comments.
269         $comment = $this->get_comment_object($u1ctx, $commentedon->id);
270         $this->setUser($u1);
271         $comment->add('Hello, it\'s me!');
272         $comment->add('I was wondering...');
273         $this->setUser($u2);
274         $comment->add('If after all these years');
275         $this->setUser($u3);
276         $comment->add('You\'d like to meet');
278         // Assert current setup.
279         $this->assertCount(6, provider::get_contexts_for_userid($u1->id)->get_contextids());
280         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
281         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
282         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
283         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
284         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
285         $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id]));
286         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u2->id]));
287         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u3->id]));
289         // Delete for u1 in cm1a.
290         $appctxs = new approved_contextlist($u1, 'core_blog', [$cm1actx->id]);
291         provider::delete_data_for_user($appctxs);
292         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
293         $this->assertCount(5, $contextids);
294         $this->assertFalse(in_array($cm1actx->id, $contextids));
295         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
296         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
297         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
298         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
299         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
300         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
302         // Delete for u1 in c1.
303         $appctxs = new approved_contextlist($u1, 'core_blog', [$c1ctx->id]);
304         provider::delete_data_for_user($appctxs);
305         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
306         $this->assertCount(4, $contextids);
307         $this->assertFalse(in_array($c1ctx->id, $contextids));
308         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
309         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
310         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
311         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
312         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
313         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
315         // Delete for u1 in c2.
316         $appctxs = new approved_contextlist($u1, 'core_blog', [$c2ctx->id]);
317         provider::delete_data_for_user($appctxs);
318         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
319         $this->assertCount(3, $contextids);
320         $this->assertFalse(in_array($c2ctx->id, $contextids));
321         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
322         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
323         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
324         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
325         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
326         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
328         // Delete for u1 in another user's context, shouldn't do anything.
329         provider::delete_data_for_user(new approved_contextlist($u1, 'core_blog', [$u2ctx->id]));
330         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
331         $this->assertCount(3, $contextids);
332         $this->assertFalse(in_array($c2ctx->id, $contextids));
333         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
334         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
335         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
336         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
337         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
338         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
339         $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id]));
340         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u2->id]));
342         // Delete for u2 in u1 context.
343         provider::delete_data_for_user(new approved_contextlist($u2, 'core_blog', [$u1ctx->id]));
344         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
345         $this->assertCount(3, $contextids);
346         $this->assertFalse(in_array($c2ctx->id, $contextids));
347         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
348         $this->assertCount(4, provider::get_contexts_for_userid($u2->id)->get_contextids());
349         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
350         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
351         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
352         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
353         $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id]));
354         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u2->id]));
355         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u3->id]));
357         // Delete for u1 in their context.
358         $appctxs = new approved_contextlist($u1, 'core_blog', [$u1ctx->id]);
359         provider::delete_data_for_user($appctxs);
360         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
361         $this->assertCount(0, $contextids);
362         $this->assertCount(1, $DB->get_records('post', ['userid' => $u1->id]));
363         $this->assertCount(4, provider::get_contexts_for_userid($u2->id)->get_contextids());
364         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
365         $this->assertCount(0, $DB->get_records('blog_external', ['userid' => $u1->id]));
366         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
367         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u1->id]));
368         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u2->id]));
369         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u3->id]));
370         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
371     }
373     public function test_delete_data_for_all_users_in_context() {
374         global $DB;
376         $dg = $this->getDataGenerator();
377         $c1 = $dg->create_course();
378         $c2 = $dg->create_course();
379         $cm1a = $dg->create_module('page', ['course' => $c1]);
380         $cm1b = $dg->create_module('page', ['course' => $c1]);
381         $cm2a = $dg->create_module('page', ['course' => $c2]);
382         $u1 = $dg->create_user();
383         $u2 = $dg->create_user();
385         $c1ctx = context_course::instance($c1->id);
386         $c2ctx = context_course::instance($c2->id);
387         $cm1actx = context_module::instance($cm1a->cmid);
388         $cm1bctx = context_module::instance($cm1b->cmid);
389         $cm2actx = context_module::instance($cm2a->cmid);
390         $u1ctx = context_user::instance($u1->id);
392         // Create two external blogs.
393         $extu1 = $this->create_external_blog(['userid' => $u1->id]);
394         $extu2 = $this->create_external_blog(['userid' => $u2->id]);
396         // Create a set of posts.
397         $entry = new blog_entry($this->create_post(['userid' => $u1->id])->id);
398         $entry = new blog_entry($this->create_post(['userid' => $u2->id])->id);
400         // Course associations for u1 and u2.
401         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
402         $entry->add_association($c1ctx->id);
403         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
404         $entry->add_association($c1ctx->id);
405         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
406         $entry->add_association($c1ctx->id);
408         // Module associations for u1 and u2.
409         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
410         $entry->add_association($cm1actx->id);
411         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
412         $entry->add_association($cm1actx->id);
413         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
414         $entry->add_association($cm1bctx->id);
415         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
416         $entry->add_association($cm1actx->id);
418         // Foreign associations for u1, u2.
419         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id);
420         $entry->add_association($c2ctx->id);
421         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c2->id])->id);
422         $entry->add_association($c2ctx->id);
423         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $cm2a->id])->id);
424         $entry->add_association($cm2actx->id);
426         // Validate what we've got.
427         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
428         $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
429         $this->assertCount(6, $contextids);
430         $this->assertTrue(in_array($c1ctx->id, $contextids));
431         $this->assertTrue(in_array($c2ctx->id, $contextids));
432         $this->assertTrue(in_array($cm1actx->id, $contextids));
433         $this->assertTrue(in_array($cm1bctx->id, $contextids));
434         $this->assertTrue(in_array($cm2actx->id, $contextids));
435         $this->assertTrue(in_array($u1ctx->id, $contextids));
436         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
437         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
438         $this->assertCount(4, $contextids);
439         $this->assertTrue(in_array($c1ctx->id, $contextids));
440         $this->assertTrue(in_array($c2ctx->id, $contextids));
441         $this->assertTrue(in_array($cm1actx->id, $contextids));
443         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
444         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
446         // Delete cm1a context.
447         provider::delete_data_for_all_users_in_context($cm1actx);
448         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
449         $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
450         $this->assertCount(5, $contextids);
451         $this->assertTrue(in_array($c1ctx->id, $contextids));
452         $this->assertTrue(in_array($c2ctx->id, $contextids));
453         $this->assertFalse(in_array($cm1actx->id, $contextids));
454         $this->assertTrue(in_array($cm1bctx->id, $contextids));
455         $this->assertTrue(in_array($cm2actx->id, $contextids));
456         $this->assertTrue(in_array($u1ctx->id, $contextids));
457         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
458         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
459         $this->assertCount(3, $contextids);
460         $this->assertTrue(in_array($c1ctx->id, $contextids));
461         $this->assertTrue(in_array($c2ctx->id, $contextids));
462         $this->assertFalse(in_array($cm1actx->id, $contextids));
464         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
465         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
467         // Delete c1 context.
468         provider::delete_data_for_all_users_in_context($c1ctx);
469         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
470         $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
471         $this->assertCount(4, $contextids);
472         $this->assertFalse(in_array($c1ctx->id, $contextids));
473         $this->assertTrue(in_array($c2ctx->id, $contextids));
474         $this->assertFalse(in_array($cm1actx->id, $contextids));
475         $this->assertTrue(in_array($cm1bctx->id, $contextids));
476         $this->assertTrue(in_array($cm2actx->id, $contextids));
477         $this->assertTrue(in_array($u1ctx->id, $contextids));
478         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
479         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
480         $this->assertCount(2, $contextids);
481         $this->assertFalse(in_array($c1ctx->id, $contextids));
482         $this->assertTrue(in_array($c2ctx->id, $contextids));
483         $this->assertFalse(in_array($cm1actx->id, $contextids));
485         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
486         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
488         // Delete u1 context.
489         provider::delete_data_for_all_users_in_context($u1ctx);
490         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
491         $this->assertCount(0, $DB->get_records('post', ['userid' => $u1->id]));
492         $this->assertCount(0, $contextids);
493         $this->assertFalse(in_array($c1ctx->id, $contextids));
494         $this->assertFalse(in_array($c2ctx->id, $contextids));
495         $this->assertFalse(in_array($cm1actx->id, $contextids));
496         $this->assertFalse(in_array($cm1bctx->id, $contextids));
497         $this->assertFalse(in_array($cm2actx->id, $contextids));
498         $this->assertFalse(in_array($u1ctx->id, $contextids));
499         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
500         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
501         $this->assertCount(2, $contextids);
502         $this->assertFalse(in_array($c1ctx->id, $contextids));
503         $this->assertTrue(in_array($c2ctx->id, $contextids));
504         $this->assertFalse(in_array($cm1actx->id, $contextids));
506         $this->assertCount(0, $DB->get_records('blog_external', ['userid' => $u1->id]));
507         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
508     }
510     public function test_export_data_for_user() {
511         global $DB;
512         $dg = $this->getDataGenerator();
514         $c1 = $dg->create_course();
515         $cm1a = $dg->create_module('page', ['course' => $c1]);
516         $cm1b = $dg->create_module('page', ['course' => $c1]);
517         $u1 = $dg->create_user();
518         $u2 = $dg->create_user();
519         $c1ctx = context_course::instance($c1->id);
520         $cm1actx = context_module::instance($cm1a->cmid);
521         $cm1bctx = context_module::instance($cm1b->cmid);
522         $u1ctx = context_user::instance($u1->id);
523         $u2ctx = context_user::instance($u2->id);
525         // System entries.
526         $e1 = new blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hello world!',
527             'publishstate' => 'public'])->id);
528         $e2 = new blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hi planet!',
529             'publishstate' => 'draft'])->id);
530         $e3 = new blog_entry($this->create_post(['userid' => $u2->id, 'subject' => 'Ignore me'])->id);
532         // Create a blog entry associated with contexts.
533         $e4 = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc'])->id);
534         $e4->add_association($c1ctx->id);
535         $e4b = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc 2'])->id);
536         $e4b->add_association($c1ctx->id);
537         $e5 = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Module assoc',
538             'publishstate' => 'public'])->id);
539         $e5->add_association($cm1actx->id);
540         $e5b = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'C/CM assoc'])->id);
541         $e5b->add_association($c1ctx->id);
542         $e5b->add_association($cm1actx->id);
543         $e6 = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id, 'subject' => 'Module assoc'])->id);
544         $e6->add_association($cm1actx->id);
546         // External blogs.
547         $ex1 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']);
548         $ex2 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://example.com', 'name' => 'Example']);
549         $ex3 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://example.com', 'name' => 'Ignore me']);
551         // Attach tags.
552         core_tag_tag::set_item_tags('core', 'post', $e1->id, $u1ctx, ['Beer', 'Golf']);
553         core_tag_tag::set_item_tags('core', 'blog_external', $ex1->id, $u1ctx, ['Car', 'Golf']);
554         core_tag_tag::set_item_tags('core', 'post', $e3->id, $u2ctx, ['ITG']);
555         core_tag_tag::set_item_tags('core', 'blog_external', $ex3->id, $u2ctx, ['DDR']);
556         core_tag_tag::set_item_tags('core', 'dontfindme', $e1->id, $u1ctx, ['Lone tag']);
558         // Attach comments.
559         $comment = $this->get_comment_object($u1ctx, $e1->id);
560         $this->setUser($u1);
561         $comment->add('Hello, it\'s me!');
562         $this->setUser($u2);
563         $comment->add('I was wondering if after');
564         $this->setUser($u1);
565         $comment = $this->get_comment_object($u2ctx, $e3->id);
566         $comment->add('All these years');
568         // Blog share a table with notes, so throw some data in there, it should not be exported.
569         $note = $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c1->id,
570             'subject' => 'ABC']);
572         // Validate module associations.
573         $contextlist = new approved_contextlist($u1, 'core_blog', [$cm1actx->id]);
574         provider::export_user_data($contextlist);
575         $writer = writer::with_context($cm1actx);
576         $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]);
577         $this->assertCount(2, $assocs->associations);
578         $this->assertTrue(in_array('Module assoc', $assocs->associations));
579         $this->assertTrue(in_array('C/CM assoc', $assocs->associations));
581         // Validate course associations.
582         $contextlist = new approved_contextlist($u1, 'core_blog', [$c1ctx->id]);
583         provider::export_user_data($contextlist);
584         $writer = writer::with_context($c1ctx);
585         $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]);
586         $this->assertCount(3, $assocs->associations);
587         $this->assertTrue(in_array('Course assoc', $assocs->associations));
588         $this->assertTrue(in_array('Course assoc 2', $assocs->associations));
589         $this->assertTrue(in_array('C/CM assoc', $assocs->associations));
591         // Confirm we're not exporting for another user.
592         $contextlist = new approved_contextlist($u2, 'core_blog', [$u2ctx->id]);
593         $writer = writer::with_context($u1ctx);
594         $this->assertFalse($writer->has_any_data());
596         // Now export user context for u2.
597         $this->setUser($u2);
598         $contextlist = new approved_contextlist($u2, 'core_blog', [$u1ctx->id]);
599         provider::export_user_data($contextlist);
600         $writer = writer::with_context($u1ctx);
601         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'),
602             $ex1->name . " ({$ex1->id})"]);
603         $this->assertEmpty($data);
604         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
605             $e2->subject . " ({$e2->id})"]);
606         $this->assertEmpty($data);
607         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
608             $e1->subject . " ({$e1->id})"]);
609         $this->assertEmpty($data);
610         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
611             $e1->subject . " ({$e1->id})", get_string('commentsubcontext', 'core_comment')]);
612         $this->assertNotEmpty($data);
613         $this->assertCount(1, $data->comments);
614         $comment = array_shift($data->comments);
615         $this->assertEquals('I was wondering if after', strip_tags($comment->content));
617         // Now export user context data.
618         $this->setUser($u1);
619         $contextlist = new approved_contextlist($u1, 'core_blog', [$u1ctx->id]);
620         writer::reset();
621         provider::export_user_data($contextlist);
622         $writer = writer::with_context($u1ctx);
624         // Check external blogs.
625         $externals = [$ex1, $ex2];
626         foreach ($externals as $ex) {
627             $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'),
628                 $ex->name . " ({$ex->id})"]);
629             $this->assertNotEmpty($data);
630             $this->assertEquals($data->name, $ex->name);
631             $this->assertEquals($data->description, $ex->description);
632             $this->assertEquals($data->url, $ex->url);
633             $this->assertEquals($data->filtertags, $ex->filtertags);
634             $this->assertEquals($data->modified, transform::datetime($ex->timemodified));
635             $this->assertEquals($data->lastfetched, transform::datetime($ex->timefetched));
636         }
638         // Check entries.
639         $entries = [$e1, $e2, $e4, $e4b, $e5, $e5b];
640         $associations = [
641             $e1->id => null,
642             $e2->id => null,
643             $e4->id => $c1ctx->get_context_name(),
644             $e4b->id => $c1ctx->get_context_name(),
645             $e5->id => $cm1actx->get_context_name(),
646             $e5b->id => [$c1ctx->get_context_name(), $cm1actx->get_context_name()],
647         ];
648         foreach ($entries as $e) {
649             $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), $e->subject . " ({$e->id})"];
650             $data = $writer->get_data($path);
651             $this->assertNotEmpty($data);
652             $this->assertEquals($data->subject, $e->subject);
653             $this->assertEquals($data->summary, $e->summary);
654             $this->assertEquals($data->publishstate, provider::transform_publishstate($e->publishstate));
655             $this->assertEquals($data->created, transform::datetime($e->created));
656             $this->assertEquals($data->lastmodified, transform::datetime($e->lastmodified));
658             // We attached comments and tags to this entry.
659             $commentpath = array_merge($path, [get_string('commentsubcontext', 'core_comment')]);
660             if ($e->id == $e1->id) {
661                 $tagdata = $writer->get_related_data($path, 'tags');
662                 $this->assertEquals(['Beer', 'Golf'], $tagdata, '', 0, 10, true);
664                 $comments = $writer->get_data($commentpath);
665                 $this->assertCount(2, $comments->comments);
667                 $c0 = strip_tags($comments->comments[0]->content);
668                 $c1 = strip_tags($comments->comments[1]->content);
669                 $expectedcomments = [
670                     'Hello, it\'s me!',
671                     'I was wondering if after',
672                 ];
674                 $this->assertNotFalse(array_search($c0, $expectedcomments));
675                 $this->assertNotFalse(array_search($c1, $expectedcomments));
676                 $this->assertNotEquals($c0, $c1);
678             } else {
679                 $tagdata = $writer->get_related_data($path, 'tags');
680                 $this->assertEmpty($tagdata);
681                 $comments = $writer->get_data($commentpath);
682                 $this->assertEmpty($comments);
683             }
685             if (isset($associations[$e->id])) {
686                 $assocs = $associations[$e->id];
687                 if (is_array($assocs)) {
688                     $this->assertCount(count($assocs), $data->associations);
689                     foreach ($assocs as $v) {
690                         $this->assertTrue(in_array($v, $data->associations));
691                     }
692                 } else {
693                     $this->assertCount(1, $data->associations);
694                     $this->assertTrue(in_array($assocs, $data->associations));
695                 }
696             }
697         }
699         // The note was not exported.
700         $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), "ABC ($note->id)"];
701         $this->assertEmpty($writer->get_data($path));
703     }
705     /**
706      * Test that deleting of blog information in a user context works as desired.
707      */
708     public function test_delete_data_for_users_user_context() {
709         global $DB;
711         $u1 = $this->getDataGenerator()->create_user();
712         $u2 = $this->getDataGenerator()->create_user();
713         $u3 = $this->getDataGenerator()->create_user();
714         $u4 = $this->getDataGenerator()->create_user();
715         $u5 = $this->getDataGenerator()->create_user();
717         $u1ctx = context_user::instance($u1->id);
719         $post = $this->create_post(['userid' => $u1->id]);
720         $entry = new blog_entry($post->id);
722         $comment = $this->get_comment_object($u1ctx, $entry->id);
723         $this->setUser($u1);
724         $comment->add('Hello, I created the blog');
725         $this->setUser($u2);
726         $comment->add('User 2 making a comment.');
727         $this->setUser($u3);
728         $comment->add('User 3 here.');
729         $this->setUser($u4);
730         $comment->add('User 4 is nice.');
731         $this->setUser($u5);
732         $comment->add('User 5 for the win.');
734         // This will only delete the comments made by user 4 and 5.
735         $this->assertCount(5, $DB->get_records('comments', ['contextid' => $u1ctx->id]));
736         $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u4->id, $u5->id]);
737         provider::delete_data_for_users($userlist);
738         $this->assertCount(3, $DB->get_records('comments', ['contextid' => $u1ctx->id]));
739         $this->assertCount(1, $DB->get_records('post', ['userid' => $u1->id]));
741         // As the owner of the post is here everything will be deleted.
742         $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]);
743         provider::delete_data_for_users($userlist);
744         $this->assertEmpty($DB->get_records('comments', ['contextid' => $u1ctx->id]));
745         $this->assertEmpty($DB->get_records('post', ['userid' => $u1->id]));
746     }
748     /**
749      * Test that deleting of an external blog in a user context works as desired.
750      */
751     public function test_delete_data_for_users_external_blog() {
752         global $DB;
754         $u1 = $this->getDataGenerator()->create_user();
755         $u2 = $this->getDataGenerator()->create_user();
757         $u1ctx = context_user::instance($u1->id);
758         $u2ctx = context_user::instance($u2->id);
760         $post = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']);
761         $post2 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://moodle.com', 'name' => 'Some other thing']);
763         // Check that we have two external blogs created.
764         $this->assertCount(2, $DB->get_records('blog_external'));
765         // This will only delete the external blog for user 1.
766         $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]);
767         provider::delete_data_for_users($userlist);
768         $this->assertCount(1, $DB->get_records('blog_external'));
769     }
771     public function test_delete_data_for_users_course_and_module_context() {
772         global $DB;
774         $u1 = $this->getDataGenerator()->create_user();
775         $u2 = $this->getDataGenerator()->create_user();
776         $u3 = $this->getDataGenerator()->create_user();
777         $u4 = $this->getDataGenerator()->create_user();
778         $u5 = $this->getDataGenerator()->create_user();
780         $course = $this->getDataGenerator()->create_course();
781         $module = $this->getDataGenerator()->create_module('page', ['course' => $course]);
783         $u1ctx = context_user::instance($u1->id);
784         $u3ctx = context_user::instance($u3->id);
785         $c1ctx = context_course::instance($course->id);
786         $cm1ctx = context_module::instance($module->cmid);
788         // Blog with course association.
789         $post1 = $this->create_post(['userid' => $u1->id, 'courseid' => $course->id]);
790         $entry1 = new blog_entry($post1->id);
791         $entry1->add_association($c1ctx->id);
793         // Blog with module association.
794         $post2 = $this->create_post(['userid' => $u3->id, 'courseid' => $course->id]);
795         $entry2 = new blog_entry($post2->id);
796         $entry2->add_association($cm1ctx->id);
798         $comment = $this->get_comment_object($u1ctx, $entry1->id);
799         $this->setUser($u1);
800         $comment->add('Hello, I created the blog');
801         $this->setUser($u2);
802         $comment->add('comment on first course blog');
803         $this->setUser($u4);
804         $comment->add('user 4 on course blog');
806         $comment = $this->get_comment_object($u3ctx, $entry2->id);
807         $this->setUser($u3);
808         $comment->add('Hello, I created the module blog');
809         $this->setUser($u2);
810         $comment->add('I am commenting on both');
811         $this->setUser($u5);
812         $comment->add('User 5 for modules');
814         $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
815         $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
816         $this->assertCount(2, $DB->get_records('blog_association'));
818         // When using the course or module context we are only removing the blog associations and the comments.
819         $userlist = new \core_privacy\local\request\approved_userlist($c1ctx, 'core_blog', [$u2->id, $u1->id, $u5->id]);
820         provider::delete_data_for_users($userlist);
821         // Only one of the blog_associations should be removed. Everything else should be as before.
822         $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
823         $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
824         $this->assertCount(1, $DB->get_records('blog_association'));
826         $userlist = new \core_privacy\local\request\approved_userlist($cm1ctx, 'core_blog', [$u2->id, $u1->id, $u3->id]);
827         provider::delete_data_for_users($userlist);
828         // Now we've removed the other association.
829         $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
830         $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
831         $this->assertEmpty($DB->get_records('blog_association'));
832     }
834     /**
835      * Create a blog post.
836      *
837      * @param array $params The params.
838      * @return stdClass
839      */
840     protected function create_post(array $params) {
841         global $DB;
842         $post = new stdClass();
843         $post->module = 'blog';
844         $post->courseid = 0;
845         $post->subject = 'the test post';
846         $post->summary = 'test post summary text';
847         $post->summaryformat = FORMAT_PLAIN;
848         $post->publishstate = 'site';
849         $post->created = time() - HOURSECS;
850         $post->lastmodified = time();
851         foreach ($params as $key => $value) {
852             $post->{$key} = $value;
853         }
855         $post->id = $DB->insert_record('post', $post);
856         return $post;
857     }
859     /**
860      * Create an extenral blog.
861      *
862      * @param array $params The params.
863      * @return stdClass
864      */
865     protected function create_external_blog(array $params) {
866         global $DB;
867         $post = new stdClass();
868         $post->name = 'test external';
869         $post->description = 'the description';
870         $post->url = 'http://example.com';
871         $post->filtertags = 'a, c, b';
872         $post->timefetched = time() - HOURSECS;
873         $post->timemodified = time();
874         foreach ($params as $key => $value) {
875             $post->{$key} = $value;
876         }
877         $post->id = $DB->insert_record('blog_external', $post);
878         return $post;
879     }
881     /**
882      * Get the comment area.
883      *
884      * @param context $context The context.
885      * @param int $itemid The item ID.
886      * @param string $component The component.
887      * @param string $area The area.
888      * @return comment
889      */
890     protected function get_comment_object(context $context, $itemid) {
891         $args = new stdClass();
892         $args->context = $context;
893         $args->course = get_course(SITEID);
894         $args->area = 'format_blog';
895         $args->itemid = $itemid;
896         $args->component = 'blog';
897         $comment = new comment($args);
898         $comment->set_post_permission(true);
899         return $comment;
900     }