Merge branch 'MDL-65896-master' of https://github.com/ryanwyllie/moodle
[moodle.git] / blog / tests / privacy_test.php
CommitLineData
ce1ec9b4
FM
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 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 */
26
27defined('MOODLE_INTERNAL') || die();
28global $CFG;
29
30use core_privacy\tests\provider_testcase;
31use core_privacy\local\request\approved_contextlist;
32use core_privacy\local\request\transform;
33use core_privacy\local\request\writer;
34use core_blog\privacy\provider;
35
36require_once($CFG->dirroot . '/blog/locallib.php');
37require_once($CFG->dirroot . '/comment/lib.php');
38
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 */
48class core_blog_privacy_testcase extends provider_testcase {
49
50 public function setUp() {
51 $this->resetAfterTest();
52 }
53
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);
65
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]);
68
69 $this->assertEmpty(provider::get_contexts_for_userid($u1->id)->get_contextids());
70 $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids());
71
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());
78
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());
88
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());
99
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 }
113
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);
119
120 $this->assertEmpty(provider::get_contexts_for_userid($u1->id)->get_contextids());
121
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 }
131
799d32fd
AG
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);
140
141 $post = $this->create_post(['userid' => $user1->id, 'courseid' => $course->id]);
142 $entry = new blog_entry($post->id);
143 $entry->add_association($c1ctx->id);
144
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');
149
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);
154
155 // Add an association for a module.
156 $cm1a = $this->getDataGenerator()->create_module('page', ['course' => $course]);
157 $cm1ctx = context_module::instance($cm1a->cmid);
158
159 $post2 = $this->create_post(['userid' => $user2->id, 'courseid' => $course->id]);
160 $entry2 = new blog_entry($post2->id);
161 $entry2->add_association($cm1ctx->id);
162
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 }
168
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);
176
177 $post = $this->create_post(['userid' => $user1->id]);
178 $entry = new blog_entry($post->id);
179
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');
184
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 }
190
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]);
198
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 }
204
ce1ec9b4
FM
205 public function test_delete_data_for_user() {
206 global $DB;
207
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();
217
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);
225
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']));
230
231 // Create two external blogs.
232 $extu1 = $this->create_external_blog(['userid' => $u1->id]);
233 $extu2 = $this->create_external_blog(['userid' => $u2->id]);
234
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);
239
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);
245
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);
253
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);
261
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);
267
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');
277
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]));
288
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']));
301
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']));
314
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']));
327
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]));
341
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]));
356
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 }
372
d95812cb
PH
373 /**
374 * Test provider delete_data_for_user with a context that contains no entries
375 *
376 * @return void
377 */
378 public function test_delete_data_for_user_empty_context() {
379 global $DB;
380
381 $user = $this->getDataGenerator()->create_user();
382 $course = $this->getDataGenerator()->create_course();
383 $context = context_course::instance($course->id);
384
385 // Create a blog entry for user, associated with course.
386 $entry = new blog_entry($this->create_post(['userid' => $user->id, 'courseid' => $course->id])->id);
387 $entry->add_association($context->id);
388
389 // Generate list of contexts for user.
390 $contexts = provider::get_contexts_for_userid($user->id);
391 $this->assertContains($context->id, $contexts->get_contextids());
392
393 // Now delete the blog entry.
394 $entry->delete();
395
396 // Try to delete user data using contexts obtained prior to entry deletion.
397 $contextlist = new approved_contextlist($user, 'core_blog', $contexts->get_contextids());
398 provider::delete_data_for_user($contextlist);
399
400 // Sanity check to ensure blog_associations is really empty.
401 $this->assertEmpty($DB->get_records('blog_association', ['contextid' => $context->id]));
402 }
403
ce1ec9b4
FM
404 public function test_delete_data_for_all_users_in_context() {
405 global $DB;
406
407 $dg = $this->getDataGenerator();
408 $c1 = $dg->create_course();
409 $c2 = $dg->create_course();
410 $cm1a = $dg->create_module('page', ['course' => $c1]);
411 $cm1b = $dg->create_module('page', ['course' => $c1]);
412 $cm2a = $dg->create_module('page', ['course' => $c2]);
413 $u1 = $dg->create_user();
414 $u2 = $dg->create_user();
415
416 $c1ctx = context_course::instance($c1->id);
417 $c2ctx = context_course::instance($c2->id);
418 $cm1actx = context_module::instance($cm1a->cmid);
419 $cm1bctx = context_module::instance($cm1b->cmid);
420 $cm2actx = context_module::instance($cm2a->cmid);
421 $u1ctx = context_user::instance($u1->id);
422
423 // Create two external blogs.
424 $extu1 = $this->create_external_blog(['userid' => $u1->id]);
425 $extu2 = $this->create_external_blog(['userid' => $u2->id]);
426
427 // Create a set of posts.
428 $entry = new blog_entry($this->create_post(['userid' => $u1->id])->id);
429 $entry = new blog_entry($this->create_post(['userid' => $u2->id])->id);
430
431 // Course associations for u1 and u2.
432 $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
433 $entry->add_association($c1ctx->id);
434 $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
435 $entry->add_association($c1ctx->id);
436 $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
437 $entry->add_association($c1ctx->id);
438
439 // Module associations for u1 and u2.
440 $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
441 $entry->add_association($cm1actx->id);
442 $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
443 $entry->add_association($cm1actx->id);
444 $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
445 $entry->add_association($cm1bctx->id);
446 $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
447 $entry->add_association($cm1actx->id);
448
449 // Foreign associations for u1, u2.
450 $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id);
451 $entry->add_association($c2ctx->id);
452 $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c2->id])->id);
453 $entry->add_association($c2ctx->id);
454 $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $cm2a->id])->id);
455 $entry->add_association($cm2actx->id);
456
457 // Validate what we've got.
458 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
459 $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
460 $this->assertCount(6, $contextids);
461 $this->assertTrue(in_array($c1ctx->id, $contextids));
462 $this->assertTrue(in_array($c2ctx->id, $contextids));
463 $this->assertTrue(in_array($cm1actx->id, $contextids));
464 $this->assertTrue(in_array($cm1bctx->id, $contextids));
465 $this->assertTrue(in_array($cm2actx->id, $contextids));
466 $this->assertTrue(in_array($u1ctx->id, $contextids));
467 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
468 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
469 $this->assertCount(4, $contextids);
470 $this->assertTrue(in_array($c1ctx->id, $contextids));
471 $this->assertTrue(in_array($c2ctx->id, $contextids));
472 $this->assertTrue(in_array($cm1actx->id, $contextids));
473
474 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
475 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
476
477 // Delete cm1a context.
478 provider::delete_data_for_all_users_in_context($cm1actx);
479 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
480 $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
481 $this->assertCount(5, $contextids);
482 $this->assertTrue(in_array($c1ctx->id, $contextids));
483 $this->assertTrue(in_array($c2ctx->id, $contextids));
484 $this->assertFalse(in_array($cm1actx->id, $contextids));
485 $this->assertTrue(in_array($cm1bctx->id, $contextids));
486 $this->assertTrue(in_array($cm2actx->id, $contextids));
487 $this->assertTrue(in_array($u1ctx->id, $contextids));
488 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
489 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
490 $this->assertCount(3, $contextids);
491 $this->assertTrue(in_array($c1ctx->id, $contextids));
492 $this->assertTrue(in_array($c2ctx->id, $contextids));
493 $this->assertFalse(in_array($cm1actx->id, $contextids));
494
495 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
496 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
497
498 // Delete c1 context.
499 provider::delete_data_for_all_users_in_context($c1ctx);
500 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
501 $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
502 $this->assertCount(4, $contextids);
503 $this->assertFalse(in_array($c1ctx->id, $contextids));
504 $this->assertTrue(in_array($c2ctx->id, $contextids));
505 $this->assertFalse(in_array($cm1actx->id, $contextids));
506 $this->assertTrue(in_array($cm1bctx->id, $contextids));
507 $this->assertTrue(in_array($cm2actx->id, $contextids));
508 $this->assertTrue(in_array($u1ctx->id, $contextids));
509 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
510 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
511 $this->assertCount(2, $contextids);
512 $this->assertFalse(in_array($c1ctx->id, $contextids));
513 $this->assertTrue(in_array($c2ctx->id, $contextids));
514 $this->assertFalse(in_array($cm1actx->id, $contextids));
515
516 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
517 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
518
519 // Delete u1 context.
520 provider::delete_data_for_all_users_in_context($u1ctx);
521 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
522 $this->assertCount(0, $DB->get_records('post', ['userid' => $u1->id]));
523 $this->assertCount(0, $contextids);
524 $this->assertFalse(in_array($c1ctx->id, $contextids));
525 $this->assertFalse(in_array($c2ctx->id, $contextids));
526 $this->assertFalse(in_array($cm1actx->id, $contextids));
527 $this->assertFalse(in_array($cm1bctx->id, $contextids));
528 $this->assertFalse(in_array($cm2actx->id, $contextids));
529 $this->assertFalse(in_array($u1ctx->id, $contextids));
530 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
531 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
532 $this->assertCount(2, $contextids);
533 $this->assertFalse(in_array($c1ctx->id, $contextids));
534 $this->assertTrue(in_array($c2ctx->id, $contextids));
535 $this->assertFalse(in_array($cm1actx->id, $contextids));
536
537 $this->assertCount(0, $DB->get_records('blog_external', ['userid' => $u1->id]));
538 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
539 }
540
541 public function test_export_data_for_user() {
542 global $DB;
543 $dg = $this->getDataGenerator();
544
545 $c1 = $dg->create_course();
546 $cm1a = $dg->create_module('page', ['course' => $c1]);
547 $cm1b = $dg->create_module('page', ['course' => $c1]);
548 $u1 = $dg->create_user();
549 $u2 = $dg->create_user();
550 $c1ctx = context_course::instance($c1->id);
551 $cm1actx = context_module::instance($cm1a->cmid);
552 $cm1bctx = context_module::instance($cm1b->cmid);
553 $u1ctx = context_user::instance($u1->id);
554 $u2ctx = context_user::instance($u2->id);
555
556 // System entries.
557 $e1 = new blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hello world!',
558 'publishstate' => 'public'])->id);
559 $e2 = new blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hi planet!',
560 'publishstate' => 'draft'])->id);
561 $e3 = new blog_entry($this->create_post(['userid' => $u2->id, 'subject' => 'Ignore me'])->id);
562
563 // Create a blog entry associated with contexts.
564 $e4 = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc'])->id);
565 $e4->add_association($c1ctx->id);
566 $e4b = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc 2'])->id);
567 $e4b->add_association($c1ctx->id);
568 $e5 = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Module assoc',
569 'publishstate' => 'public'])->id);
570 $e5->add_association($cm1actx->id);
571 $e5b = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'C/CM assoc'])->id);
572 $e5b->add_association($c1ctx->id);
573 $e5b->add_association($cm1actx->id);
574 $e6 = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id, 'subject' => 'Module assoc'])->id);
575 $e6->add_association($cm1actx->id);
576
577 // External blogs.
578 $ex1 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']);
579 $ex2 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://example.com', 'name' => 'Example']);
580 $ex3 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://example.com', 'name' => 'Ignore me']);
581
582 // Attach tags.
583 core_tag_tag::set_item_tags('core', 'post', $e1->id, $u1ctx, ['Beer', 'Golf']);
584 core_tag_tag::set_item_tags('core', 'blog_external', $ex1->id, $u1ctx, ['Car', 'Golf']);
585 core_tag_tag::set_item_tags('core', 'post', $e3->id, $u2ctx, ['ITG']);
586 core_tag_tag::set_item_tags('core', 'blog_external', $ex3->id, $u2ctx, ['DDR']);
587 core_tag_tag::set_item_tags('core', 'dontfindme', $e1->id, $u1ctx, ['Lone tag']);
588
589 // Attach comments.
590 $comment = $this->get_comment_object($u1ctx, $e1->id);
591 $this->setUser($u1);
592 $comment->add('Hello, it\'s me!');
593 $this->setUser($u2);
594 $comment->add('I was wondering if after');
595 $this->setUser($u1);
596 $comment = $this->get_comment_object($u2ctx, $e3->id);
597 $comment->add('All these years');
598
599 // Blog share a table with notes, so throw some data in there, it should not be exported.
600 $note = $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c1->id,
601 'subject' => 'ABC']);
602
603 // Validate module associations.
604 $contextlist = new approved_contextlist($u1, 'core_blog', [$cm1actx->id]);
605 provider::export_user_data($contextlist);
606 $writer = writer::with_context($cm1actx);
607 $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]);
608 $this->assertCount(2, $assocs->associations);
609 $this->assertTrue(in_array('Module assoc', $assocs->associations));
610 $this->assertTrue(in_array('C/CM assoc', $assocs->associations));
611
612 // Validate course associations.
613 $contextlist = new approved_contextlist($u1, 'core_blog', [$c1ctx->id]);
614 provider::export_user_data($contextlist);
615 $writer = writer::with_context($c1ctx);
616 $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]);
617 $this->assertCount(3, $assocs->associations);
618 $this->assertTrue(in_array('Course assoc', $assocs->associations));
619 $this->assertTrue(in_array('Course assoc 2', $assocs->associations));
620 $this->assertTrue(in_array('C/CM assoc', $assocs->associations));
621
622 // Confirm we're not exporting for another user.
623 $contextlist = new approved_contextlist($u2, 'core_blog', [$u2ctx->id]);
624 $writer = writer::with_context($u1ctx);
625 $this->assertFalse($writer->has_any_data());
626
627 // Now export user context for u2.
628 $this->setUser($u2);
629 $contextlist = new approved_contextlist($u2, 'core_blog', [$u1ctx->id]);
630 provider::export_user_data($contextlist);
631 $writer = writer::with_context($u1ctx);
632 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'),
633 $ex1->name . " ({$ex1->id})"]);
634 $this->assertEmpty($data);
635 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
636 $e2->subject . " ({$e2->id})"]);
637 $this->assertEmpty($data);
638 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
639 $e1->subject . " ({$e1->id})"]);
640 $this->assertEmpty($data);
641 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
642 $e1->subject . " ({$e1->id})", get_string('commentsubcontext', 'core_comment')]);
643 $this->assertNotEmpty($data);
644 $this->assertCount(1, $data->comments);
645 $comment = array_shift($data->comments);
646 $this->assertEquals('I was wondering if after', strip_tags($comment->content));
647
648 // Now export user context data.
649 $this->setUser($u1);
650 $contextlist = new approved_contextlist($u1, 'core_blog', [$u1ctx->id]);
651 writer::reset();
652 provider::export_user_data($contextlist);
653 $writer = writer::with_context($u1ctx);
654
655 // Check external blogs.
656 $externals = [$ex1, $ex2];
657 foreach ($externals as $ex) {
658 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'),
659 $ex->name . " ({$ex->id})"]);
660 $this->assertNotEmpty($data);
661 $this->assertEquals($data->name, $ex->name);
662 $this->assertEquals($data->description, $ex->description);
663 $this->assertEquals($data->url, $ex->url);
664 $this->assertEquals($data->filtertags, $ex->filtertags);
665 $this->assertEquals($data->modified, transform::datetime($ex->timemodified));
666 $this->assertEquals($data->lastfetched, transform::datetime($ex->timefetched));
667 }
668
669 // Check entries.
670 $entries = [$e1, $e2, $e4, $e4b, $e5, $e5b];
671 $associations = [
672 $e1->id => null,
673 $e2->id => null,
674 $e4->id => $c1ctx->get_context_name(),
675 $e4b->id => $c1ctx->get_context_name(),
676 $e5->id => $cm1actx->get_context_name(),
677 $e5b->id => [$c1ctx->get_context_name(), $cm1actx->get_context_name()],
678 ];
679 foreach ($entries as $e) {
680 $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), $e->subject . " ({$e->id})"];
681 $data = $writer->get_data($path);
682 $this->assertNotEmpty($data);
683 $this->assertEquals($data->subject, $e->subject);
684 $this->assertEquals($data->summary, $e->summary);
685 $this->assertEquals($data->publishstate, provider::transform_publishstate($e->publishstate));
686 $this->assertEquals($data->created, transform::datetime($e->created));
687 $this->assertEquals($data->lastmodified, transform::datetime($e->lastmodified));
688
689 // We attached comments and tags to this entry.
690 $commentpath = array_merge($path, [get_string('commentsubcontext', 'core_comment')]);
691 if ($e->id == $e1->id) {
692 $tagdata = $writer->get_related_data($path, 'tags');
2207b0fa 693 $this->assertEquals(['Beer', 'Golf'], $tagdata, '', 0, 10, true);
ce1ec9b4
FM
694
695 $comments = $writer->get_data($commentpath);
696 $this->assertCount(2, $comments->comments);
70720094
AN
697
698 $c0 = strip_tags($comments->comments[0]->content);
699 $c1 = strip_tags($comments->comments[1]->content);
700 $expectedcomments = [
701 'Hello, it\'s me!',
702 'I was wondering if after',
703 ];
704
705 $this->assertNotFalse(array_search($c0, $expectedcomments));
706 $this->assertNotFalse(array_search($c1, $expectedcomments));
707 $this->assertNotEquals($c0, $c1);
ce1ec9b4
FM
708
709 } else {
710 $tagdata = $writer->get_related_data($path, 'tags');
711 $this->assertEmpty($tagdata);
712 $comments = $writer->get_data($commentpath);
713 $this->assertEmpty($comments);
714 }
715
716 if (isset($associations[$e->id])) {
717 $assocs = $associations[$e->id];
718 if (is_array($assocs)) {
719 $this->assertCount(count($assocs), $data->associations);
720 foreach ($assocs as $v) {
721 $this->assertTrue(in_array($v, $data->associations));
722 }
723 } else {
724 $this->assertCount(1, $data->associations);
725 $this->assertTrue(in_array($assocs, $data->associations));
726 }
727 }
728 }
729
730 // The note was not exported.
731 $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), "ABC ($note->id)"];
732 $this->assertEmpty($writer->get_data($path));
733
734 }
735
799d32fd
AG
736 /**
737 * Test that deleting of blog information in a user context works as desired.
738 */
739 public function test_delete_data_for_users_user_context() {
740 global $DB;
741
742 $u1 = $this->getDataGenerator()->create_user();
743 $u2 = $this->getDataGenerator()->create_user();
744 $u3 = $this->getDataGenerator()->create_user();
745 $u4 = $this->getDataGenerator()->create_user();
746 $u5 = $this->getDataGenerator()->create_user();
747
748 $u1ctx = context_user::instance($u1->id);
749
750 $post = $this->create_post(['userid' => $u1->id]);
751 $entry = new blog_entry($post->id);
752
753 $comment = $this->get_comment_object($u1ctx, $entry->id);
754 $this->setUser($u1);
755 $comment->add('Hello, I created the blog');
756 $this->setUser($u2);
757 $comment->add('User 2 making a comment.');
758 $this->setUser($u3);
759 $comment->add('User 3 here.');
760 $this->setUser($u4);
761 $comment->add('User 4 is nice.');
762 $this->setUser($u5);
763 $comment->add('User 5 for the win.');
764
765 // This will only delete the comments made by user 4 and 5.
766 $this->assertCount(5, $DB->get_records('comments', ['contextid' => $u1ctx->id]));
767 $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u4->id, $u5->id]);
768 provider::delete_data_for_users($userlist);
769 $this->assertCount(3, $DB->get_records('comments', ['contextid' => $u1ctx->id]));
770 $this->assertCount(1, $DB->get_records('post', ['userid' => $u1->id]));
771
772 // As the owner of the post is here everything will be deleted.
773 $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]);
774 provider::delete_data_for_users($userlist);
775 $this->assertEmpty($DB->get_records('comments', ['contextid' => $u1ctx->id]));
776 $this->assertEmpty($DB->get_records('post', ['userid' => $u1->id]));
777 }
778
779 /**
780 * Test that deleting of an external blog in a user context works as desired.
781 */
782 public function test_delete_data_for_users_external_blog() {
783 global $DB;
784
785 $u1 = $this->getDataGenerator()->create_user();
786 $u2 = $this->getDataGenerator()->create_user();
787
788 $u1ctx = context_user::instance($u1->id);
789 $u2ctx = context_user::instance($u2->id);
790
791 $post = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']);
792 $post2 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://moodle.com', 'name' => 'Some other thing']);
793
794 // Check that we have two external blogs created.
795 $this->assertCount(2, $DB->get_records('blog_external'));
796 // This will only delete the external blog for user 1.
797 $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]);
798 provider::delete_data_for_users($userlist);
799 $this->assertCount(1, $DB->get_records('blog_external'));
800 }
801
802 public function test_delete_data_for_users_course_and_module_context() {
803 global $DB;
804
805 $u1 = $this->getDataGenerator()->create_user();
806 $u2 = $this->getDataGenerator()->create_user();
807 $u3 = $this->getDataGenerator()->create_user();
808 $u4 = $this->getDataGenerator()->create_user();
809 $u5 = $this->getDataGenerator()->create_user();
810
811 $course = $this->getDataGenerator()->create_course();
812 $module = $this->getDataGenerator()->create_module('page', ['course' => $course]);
813
814 $u1ctx = context_user::instance($u1->id);
815 $u3ctx = context_user::instance($u3->id);
816 $c1ctx = context_course::instance($course->id);
817 $cm1ctx = context_module::instance($module->cmid);
818
819 // Blog with course association.
820 $post1 = $this->create_post(['userid' => $u1->id, 'courseid' => $course->id]);
821 $entry1 = new blog_entry($post1->id);
822 $entry1->add_association($c1ctx->id);
823
824 // Blog with module association.
825 $post2 = $this->create_post(['userid' => $u3->id, 'courseid' => $course->id]);
826 $entry2 = new blog_entry($post2->id);
827 $entry2->add_association($cm1ctx->id);
828
829 $comment = $this->get_comment_object($u1ctx, $entry1->id);
830 $this->setUser($u1);
831 $comment->add('Hello, I created the blog');
832 $this->setUser($u2);
833 $comment->add('comment on first course blog');
834 $this->setUser($u4);
835 $comment->add('user 4 on course blog');
836
837 $comment = $this->get_comment_object($u3ctx, $entry2->id);
838 $this->setUser($u3);
839 $comment->add('Hello, I created the module blog');
840 $this->setUser($u2);
841 $comment->add('I am commenting on both');
842 $this->setUser($u5);
843 $comment->add('User 5 for modules');
844
845 $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
846 $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
847 $this->assertCount(2, $DB->get_records('blog_association'));
848
849 // When using the course or module context we are only removing the blog associations and the comments.
850 $userlist = new \core_privacy\local\request\approved_userlist($c1ctx, 'core_blog', [$u2->id, $u1->id, $u5->id]);
851 provider::delete_data_for_users($userlist);
852 // Only one of the blog_associations should be removed. Everything else should be as before.
853 $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
854 $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
855 $this->assertCount(1, $DB->get_records('blog_association'));
856
857 $userlist = new \core_privacy\local\request\approved_userlist($cm1ctx, 'core_blog', [$u2->id, $u1->id, $u3->id]);
858 provider::delete_data_for_users($userlist);
859 // Now we've removed the other association.
860 $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
861 $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
862 $this->assertEmpty($DB->get_records('blog_association'));
863 }
864
ce1ec9b4
FM
865 /**
866 * Create a blog post.
867 *
868 * @param array $params The params.
869 * @return stdClass
870 */
871 protected function create_post(array $params) {
872 global $DB;
873 $post = new stdClass();
874 $post->module = 'blog';
875 $post->courseid = 0;
876 $post->subject = 'the test post';
877 $post->summary = 'test post summary text';
878 $post->summaryformat = FORMAT_PLAIN;
879 $post->publishstate = 'site';
880 $post->created = time() - HOURSECS;
881 $post->lastmodified = time();
882 foreach ($params as $key => $value) {
883 $post->{$key} = $value;
884 }
885
886 $post->id = $DB->insert_record('post', $post);
887 return $post;
888 }
889
890 /**
891 * Create an extenral blog.
892 *
893 * @param array $params The params.
894 * @return stdClass
895 */
896 protected function create_external_blog(array $params) {
897 global $DB;
898 $post = new stdClass();
899 $post->name = 'test external';
900 $post->description = 'the description';
901 $post->url = 'http://example.com';
902 $post->filtertags = 'a, c, b';
903 $post->timefetched = time() - HOURSECS;
904 $post->timemodified = time();
905 foreach ($params as $key => $value) {
906 $post->{$key} = $value;
907 }
908 $post->id = $DB->insert_record('blog_external', $post);
909 return $post;
910 }
911
912 /**
913 * Get the comment area.
914 *
915 * @param context $context The context.
916 * @param int $itemid The item ID.
917 * @param string $component The component.
918 * @param string $area The area.
919 * @return comment
920 */
921 protected function get_comment_object(context $context, $itemid) {
922 $args = new stdClass();
923 $args->context = $context;
924 $args->course = get_course(SITEID);
925 $args->area = 'format_blog';
926 $args->itemid = $itemid;
927 $args->component = 'blog';
928 $comment = new comment($args);
929 $comment->set_post_permission(true);
930 return $comment;
931 }
932}