MDL-61836 core_blog: Implement privacy API
[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     public function test_delete_data_for_user() {
133         global $DB;
135         $dg = $this->getDataGenerator();
136         $c1 = $dg->create_course();
137         $c2 = $dg->create_course();
138         $cm1a = $dg->create_module('page', ['course' => $c1]);
139         $cm1b = $dg->create_module('page', ['course' => $c1]);
140         $cm2a = $dg->create_module('page', ['course' => $c2]);
141         $u1 = $dg->create_user();
142         $u2 = $dg->create_user();
143         $u3 = $dg->create_user();
145         $c1ctx = context_course::instance($c1->id);
146         $c2ctx = context_course::instance($c2->id);
147         $cm1actx = context_module::instance($cm1a->cmid);
148         $cm1bctx = context_module::instance($cm1b->cmid);
149         $cm2actx = context_module::instance($cm2a->cmid);
150         $u1ctx = context_user::instance($u1->id);
151         $u2ctx = context_user::instance($u2->id);
153         // Blog share a table with notes, so throw data in there and make sure it doesn't get deleted.
154         $this->assertFalse($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
155         $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c1->id]);
156         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
158         // Create two external blogs.
159         $extu1 = $this->create_external_blog(['userid' => $u1->id]);
160         $extu2 = $this->create_external_blog(['userid' => $u2->id]);
162         // Create a set of posts.
163         $entry = new blog_entry($this->create_post(['userid' => $u1->id])->id);
164         $commentedon = $entry;
165         $entry = new blog_entry($this->create_post(['userid' => $u2->id])->id);
167         // Two course associations for u1.
168         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
169         $entry->add_association($c1ctx->id);
170         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
171         $entry->add_association($c1ctx->id);
173         // Two module associations with cm1a, and 1 with cm1b for u1.
174         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
175         $entry->add_association($cm1actx->id);
176         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
177         $entry->add_association($cm1actx->id);
178         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
179         $entry->add_association($cm1bctx->id);
181         // One association for u2 in c1, cm1a and cm2a.
182         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
183         $entry->add_association($c1ctx->id);
184         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
185         $entry->add_association($cm1actx->id);
186         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c2->id])->id);
187         $entry->add_association($cm2actx->id);
189         // One association for u1 in c2 and cm2a.
190         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id);
191         $entry->add_association($c2ctx->id);
192         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id);
193         $entry->add_association($cm2actx->id);
195         // Add comments.
196         $comment = $this->get_comment_object($u1ctx, $commentedon->id);
197         $this->setUser($u1);
198         $comment->add('Hello, it\'s me!');
199         $comment->add('I was wondering...');
200         $this->setUser($u2);
201         $comment->add('If after all these years');
202         $this->setUser($u3);
203         $comment->add('You\'d like to meet');
205         // Assert current setup.
206         $this->assertCount(6, provider::get_contexts_for_userid($u1->id)->get_contextids());
207         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
208         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
209         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
210         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
211         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
212         $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id]));
213         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u2->id]));
214         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u3->id]));
216         // Delete for u1 in cm1a.
217         $appctxs = new approved_contextlist($u1, 'core_blog', [$cm1actx->id]);
218         provider::delete_data_for_user($appctxs);
219         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
220         $this->assertCount(5, $contextids);
221         $this->assertFalse(in_array($cm1actx->id, $contextids));
222         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
223         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
224         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
225         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
226         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
227         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
229         // Delete for u1 in c1.
230         $appctxs = new approved_contextlist($u1, 'core_blog', [$c1ctx->id]);
231         provider::delete_data_for_user($appctxs);
232         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
233         $this->assertCount(4, $contextids);
234         $this->assertFalse(in_array($c1ctx->id, $contextids));
235         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
236         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
237         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
238         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
239         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
240         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
242         // Delete for u1 in c2.
243         $appctxs = new approved_contextlist($u1, 'core_blog', [$c2ctx->id]);
244         provider::delete_data_for_user($appctxs);
245         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
246         $this->assertCount(3, $contextids);
247         $this->assertFalse(in_array($c2ctx->id, $contextids));
248         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
249         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
250         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
251         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
252         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
253         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
255         // Delete for u1 in another user's context, shouldn't do anything.
256         provider::delete_data_for_user(new approved_contextlist($u1, 'core_blog', [$u2ctx->id]));
257         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
258         $this->assertCount(3, $contextids);
259         $this->assertFalse(in_array($c2ctx->id, $contextids));
260         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
261         $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids());
262         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
263         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
264         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
265         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
266         $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id]));
267         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u2->id]));
269         // Delete for u2 in u1 context.
270         provider::delete_data_for_user(new approved_contextlist($u2, 'core_blog', [$u1ctx->id]));
271         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
272         $this->assertCount(3, $contextids);
273         $this->assertFalse(in_array($c2ctx->id, $contextids));
274         $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id]));
275         $this->assertCount(4, provider::get_contexts_for_userid($u2->id)->get_contextids());
276         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
277         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
278         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
279         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
280         $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id]));
281         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u2->id]));
282         $this->assertCount(1, $DB->get_records('comments', ['userid' => $u3->id]));
284         // Delete for u1 in their context.
285         $appctxs = new approved_contextlist($u1, 'core_blog', [$u1ctx->id]);
286         provider::delete_data_for_user($appctxs);
287         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
288         $this->assertCount(0, $contextids);
289         $this->assertCount(1, $DB->get_records('post', ['userid' => $u1->id]));
290         $this->assertCount(4, provider::get_contexts_for_userid($u2->id)->get_contextids());
291         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
292         $this->assertCount(0, $DB->get_records('blog_external', ['userid' => $u1->id]));
293         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
294         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u1->id]));
295         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u2->id]));
296         $this->assertCount(0, $DB->get_records('comments', ['userid' => $u3->id]));
297         $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
298     }
300     public function test_delete_data_for_all_users_in_context() {
301         global $DB;
303         $dg = $this->getDataGenerator();
304         $c1 = $dg->create_course();
305         $c2 = $dg->create_course();
306         $cm1a = $dg->create_module('page', ['course' => $c1]);
307         $cm1b = $dg->create_module('page', ['course' => $c1]);
308         $cm2a = $dg->create_module('page', ['course' => $c2]);
309         $u1 = $dg->create_user();
310         $u2 = $dg->create_user();
312         $c1ctx = context_course::instance($c1->id);
313         $c2ctx = context_course::instance($c2->id);
314         $cm1actx = context_module::instance($cm1a->cmid);
315         $cm1bctx = context_module::instance($cm1b->cmid);
316         $cm2actx = context_module::instance($cm2a->cmid);
317         $u1ctx = context_user::instance($u1->id);
319         // Create two external blogs.
320         $extu1 = $this->create_external_blog(['userid' => $u1->id]);
321         $extu2 = $this->create_external_blog(['userid' => $u2->id]);
323         // Create a set of posts.
324         $entry = new blog_entry($this->create_post(['userid' => $u1->id])->id);
325         $entry = new blog_entry($this->create_post(['userid' => $u2->id])->id);
327         // Course associations for u1 and u2.
328         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
329         $entry->add_association($c1ctx->id);
330         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
331         $entry->add_association($c1ctx->id);
332         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
333         $entry->add_association($c1ctx->id);
335         // Module associations for u1 and u2.
336         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
337         $entry->add_association($cm1actx->id);
338         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
339         $entry->add_association($cm1actx->id);
340         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id);
341         $entry->add_association($cm1bctx->id);
342         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id);
343         $entry->add_association($cm1actx->id);
345         // Foreign associations for u1, u2.
346         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id);
347         $entry->add_association($c2ctx->id);
348         $entry = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c2->id])->id);
349         $entry->add_association($c2ctx->id);
350         $entry = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $cm2a->id])->id);
351         $entry->add_association($cm2actx->id);
353         // Validate what we've got.
354         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
355         $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
356         $this->assertCount(6, $contextids);
357         $this->assertTrue(in_array($c1ctx->id, $contextids));
358         $this->assertTrue(in_array($c2ctx->id, $contextids));
359         $this->assertTrue(in_array($cm1actx->id, $contextids));
360         $this->assertTrue(in_array($cm1bctx->id, $contextids));
361         $this->assertTrue(in_array($cm2actx->id, $contextids));
362         $this->assertTrue(in_array($u1ctx->id, $contextids));
363         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
364         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
365         $this->assertCount(4, $contextids);
366         $this->assertTrue(in_array($c1ctx->id, $contextids));
367         $this->assertTrue(in_array($c2ctx->id, $contextids));
368         $this->assertTrue(in_array($cm1actx->id, $contextids));
370         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
371         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
373         // Delete cm1a context.
374         provider::delete_data_for_all_users_in_context($cm1actx);
375         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
376         $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
377         $this->assertCount(5, $contextids);
378         $this->assertTrue(in_array($c1ctx->id, $contextids));
379         $this->assertTrue(in_array($c2ctx->id, $contextids));
380         $this->assertFalse(in_array($cm1actx->id, $contextids));
381         $this->assertTrue(in_array($cm1bctx->id, $contextids));
382         $this->assertTrue(in_array($cm2actx->id, $contextids));
383         $this->assertTrue(in_array($u1ctx->id, $contextids));
384         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
385         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
386         $this->assertCount(3, $contextids);
387         $this->assertTrue(in_array($c1ctx->id, $contextids));
388         $this->assertTrue(in_array($c2ctx->id, $contextids));
389         $this->assertFalse(in_array($cm1actx->id, $contextids));
391         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
392         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
394         // Delete c1 context.
395         provider::delete_data_for_all_users_in_context($c1ctx);
396         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
397         $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id]));
398         $this->assertCount(4, $contextids);
399         $this->assertFalse(in_array($c1ctx->id, $contextids));
400         $this->assertTrue(in_array($c2ctx->id, $contextids));
401         $this->assertFalse(in_array($cm1actx->id, $contextids));
402         $this->assertTrue(in_array($cm1bctx->id, $contextids));
403         $this->assertTrue(in_array($cm2actx->id, $contextids));
404         $this->assertTrue(in_array($u1ctx->id, $contextids));
405         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
406         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
407         $this->assertCount(2, $contextids);
408         $this->assertFalse(in_array($c1ctx->id, $contextids));
409         $this->assertTrue(in_array($c2ctx->id, $contextids));
410         $this->assertFalse(in_array($cm1actx->id, $contextids));
412         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id]));
413         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
415         // Delete u1 context.
416         provider::delete_data_for_all_users_in_context($u1ctx);
417         $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
418         $this->assertCount(0, $DB->get_records('post', ['userid' => $u1->id]));
419         $this->assertCount(0, $contextids);
420         $this->assertFalse(in_array($c1ctx->id, $contextids));
421         $this->assertFalse(in_array($c2ctx->id, $contextids));
422         $this->assertFalse(in_array($cm1actx->id, $contextids));
423         $this->assertFalse(in_array($cm1bctx->id, $contextids));
424         $this->assertFalse(in_array($cm2actx->id, $contextids));
425         $this->assertFalse(in_array($u1ctx->id, $contextids));
426         $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
427         $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id]));
428         $this->assertCount(2, $contextids);
429         $this->assertFalse(in_array($c1ctx->id, $contextids));
430         $this->assertTrue(in_array($c2ctx->id, $contextids));
431         $this->assertFalse(in_array($cm1actx->id, $contextids));
433         $this->assertCount(0, $DB->get_records('blog_external', ['userid' => $u1->id]));
434         $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id]));
435     }
437     public function test_export_data_for_user() {
438         global $DB;
439         $dg = $this->getDataGenerator();
441         $c1 = $dg->create_course();
442         $cm1a = $dg->create_module('page', ['course' => $c1]);
443         $cm1b = $dg->create_module('page', ['course' => $c1]);
444         $u1 = $dg->create_user();
445         $u2 = $dg->create_user();
446         $c1ctx = context_course::instance($c1->id);
447         $cm1actx = context_module::instance($cm1a->cmid);
448         $cm1bctx = context_module::instance($cm1b->cmid);
449         $u1ctx = context_user::instance($u1->id);
450         $u2ctx = context_user::instance($u2->id);
452         // System entries.
453         $e1 = new blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hello world!',
454             'publishstate' => 'public'])->id);
455         $e2 = new blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hi planet!',
456             'publishstate' => 'draft'])->id);
457         $e3 = new blog_entry($this->create_post(['userid' => $u2->id, 'subject' => 'Ignore me'])->id);
459         // Create a blog entry associated with contexts.
460         $e4 = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc'])->id);
461         $e4->add_association($c1ctx->id);
462         $e4b = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc 2'])->id);
463         $e4b->add_association($c1ctx->id);
464         $e5 = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Module assoc',
465             'publishstate' => 'public'])->id);
466         $e5->add_association($cm1actx->id);
467         $e5b = new blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'C/CM assoc'])->id);
468         $e5b->add_association($c1ctx->id);
469         $e5b->add_association($cm1actx->id);
470         $e6 = new blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id, 'subject' => 'Module assoc'])->id);
471         $e6->add_association($cm1actx->id);
473         // External blogs.
474         $ex1 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']);
475         $ex2 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://example.com', 'name' => 'Example']);
476         $ex3 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://example.com', 'name' => 'Ignore me']);
478         // Attach tags.
479         core_tag_tag::set_item_tags('core', 'post', $e1->id, $u1ctx, ['Beer', 'Golf']);
480         core_tag_tag::set_item_tags('core', 'blog_external', $ex1->id, $u1ctx, ['Car', 'Golf']);
481         core_tag_tag::set_item_tags('core', 'post', $e3->id, $u2ctx, ['ITG']);
482         core_tag_tag::set_item_tags('core', 'blog_external', $ex3->id, $u2ctx, ['DDR']);
483         core_tag_tag::set_item_tags('core', 'dontfindme', $e1->id, $u1ctx, ['Lone tag']);
485         // Attach comments.
486         $comment = $this->get_comment_object($u1ctx, $e1->id);
487         $this->setUser($u1);
488         $comment->add('Hello, it\'s me!');
489         $this->setUser($u2);
490         $comment->add('I was wondering if after');
491         $this->setUser($u1);
492         $comment = $this->get_comment_object($u2ctx, $e3->id);
493         $comment->add('All these years');
495         // Blog share a table with notes, so throw some data in there, it should not be exported.
496         $note = $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c1->id,
497             'subject' => 'ABC']);
499         // Validate module associations.
500         $contextlist = new approved_contextlist($u1, 'core_blog', [$cm1actx->id]);
501         provider::export_user_data($contextlist);
502         $writer = writer::with_context($cm1actx);
503         $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]);
504         $this->assertCount(2, $assocs->associations);
505         $this->assertTrue(in_array('Module assoc', $assocs->associations));
506         $this->assertTrue(in_array('C/CM assoc', $assocs->associations));
508         // Validate course associations.
509         $contextlist = new approved_contextlist($u1, 'core_blog', [$c1ctx->id]);
510         provider::export_user_data($contextlist);
511         $writer = writer::with_context($c1ctx);
512         $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]);
513         $this->assertCount(3, $assocs->associations);
514         $this->assertTrue(in_array('Course assoc', $assocs->associations));
515         $this->assertTrue(in_array('Course assoc 2', $assocs->associations));
516         $this->assertTrue(in_array('C/CM assoc', $assocs->associations));
518         // Confirm we're not exporting for another user.
519         $contextlist = new approved_contextlist($u2, 'core_blog', [$u2ctx->id]);
520         $writer = writer::with_context($u1ctx);
521         $this->assertFalse($writer->has_any_data());
523         // Now export user context for u2.
524         $this->setUser($u2);
525         $contextlist = new approved_contextlist($u2, 'core_blog', [$u1ctx->id]);
526         provider::export_user_data($contextlist);
527         $writer = writer::with_context($u1ctx);
528         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'),
529             $ex1->name . " ({$ex1->id})"]);
530         $this->assertEmpty($data);
531         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
532             $e2->subject . " ({$e2->id})"]);
533         $this->assertEmpty($data);
534         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
535             $e1->subject . " ({$e1->id})"]);
536         $this->assertEmpty($data);
537         $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'),
538             $e1->subject . " ({$e1->id})", get_string('commentsubcontext', 'core_comment')]);
539         $this->assertNotEmpty($data);
540         $this->assertCount(1, $data->comments);
541         $comment = array_shift($data->comments);
542         $this->assertEquals('I was wondering if after', strip_tags($comment->content));
544         // Now export user context data.
545         $this->setUser($u1);
546         $contextlist = new approved_contextlist($u1, 'core_blog', [$u1ctx->id]);
547         writer::reset();
548         provider::export_user_data($contextlist);
549         $writer = writer::with_context($u1ctx);
551         // Check external blogs.
552         $externals = [$ex1, $ex2];
553         foreach ($externals as $ex) {
554             $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'),
555                 $ex->name . " ({$ex->id})"]);
556             $this->assertNotEmpty($data);
557             $this->assertEquals($data->name, $ex->name);
558             $this->assertEquals($data->description, $ex->description);
559             $this->assertEquals($data->url, $ex->url);
560             $this->assertEquals($data->filtertags, $ex->filtertags);
561             $this->assertEquals($data->modified, transform::datetime($ex->timemodified));
562             $this->assertEquals($data->lastfetched, transform::datetime($ex->timefetched));
563         }
565         // Check entries.
566         $entries = [$e1, $e2, $e4, $e4b, $e5, $e5b];
567         $associations = [
568             $e1->id => null,
569             $e2->id => null,
570             $e4->id => $c1ctx->get_context_name(),
571             $e4b->id => $c1ctx->get_context_name(),
572             $e5->id => $cm1actx->get_context_name(),
573             $e5b->id => [$c1ctx->get_context_name(), $cm1actx->get_context_name()],
574         ];
575         foreach ($entries as $e) {
576             $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), $e->subject . " ({$e->id})"];
577             $data = $writer->get_data($path);
578             $this->assertNotEmpty($data);
579             $this->assertEquals($data->subject, $e->subject);
580             $this->assertEquals($data->summary, $e->summary);
581             $this->assertEquals($data->publishstate, provider::transform_publishstate($e->publishstate));
582             $this->assertEquals($data->created, transform::datetime($e->created));
583             $this->assertEquals($data->lastmodified, transform::datetime($e->lastmodified));
585             // We attached comments and tags to this entry.
586             $commentpath = array_merge($path, [get_string('commentsubcontext', 'core_comment')]);
587             if ($e->id == $e1->id) {
588                 $tagdata = $writer->get_related_data($path, 'tags');
589                 $this->assertCount(2, $tagdata);
590                 $tag = array_shift($tagdata);
591                 $this->assertEquals('Beer', $tag->rawname);
592                 $tag = array_shift($tagdata);
593                 $this->assertEquals('Golf', $tag->rawname);
595                 $comments = $writer->get_data($commentpath);
596                 $this->assertCount(2, $comments->comments);
597                 $this->assertEquals('Hello, it\'s me!', strip_tags($comments->comments[0]->content));
598                 $this->assertEquals('I was wondering if after', strip_tags($comments->comments[1]->content));
600             } else {
601                 $tagdata = $writer->get_related_data($path, 'tags');
602                 $this->assertEmpty($tagdata);
603                 $comments = $writer->get_data($commentpath);
604                 $this->assertEmpty($comments);
605             }
607             if (isset($associations[$e->id])) {
608                 $assocs = $associations[$e->id];
609                 if (is_array($assocs)) {
610                     $this->assertCount(count($assocs), $data->associations);
611                     foreach ($assocs as $v) {
612                         $this->assertTrue(in_array($v, $data->associations));
613                     }
614                 } else {
615                     $this->assertCount(1, $data->associations);
616                     $this->assertTrue(in_array($assocs, $data->associations));
617                 }
618             }
619         }
621         // The note was not exported.
622         $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), "ABC ($note->id)"];
623         $this->assertEmpty($writer->get_data($path));
625     }
627     /**
628      * Create a blog post.
629      *
630      * @param array $params The params.
631      * @return stdClass
632      */
633     protected function create_post(array $params) {
634         global $DB;
635         $post = new stdClass();
636         $post->module = 'blog';
637         $post->courseid = 0;
638         $post->subject = 'the test post';
639         $post->summary = 'test post summary text';
640         $post->summaryformat = FORMAT_PLAIN;
641         $post->publishstate = 'site';
642         $post->created = time() - HOURSECS;
643         $post->lastmodified = time();
644         foreach ($params as $key => $value) {
645             $post->{$key} = $value;
646         }
648         $post->id = $DB->insert_record('post', $post);
649         return $post;
650     }
652     /**
653      * Create an extenral blog.
654      *
655      * @param array $params The params.
656      * @return stdClass
657      */
658     protected function create_external_blog(array $params) {
659         global $DB;
660         $post = new stdClass();
661         $post->name = 'test external';
662         $post->description = 'the description';
663         $post->url = 'http://example.com';
664         $post->filtertags = 'a, c, b';
665         $post->timefetched = time() - HOURSECS;
666         $post->timemodified = time();
667         foreach ($params as $key => $value) {
668             $post->{$key} = $value;
669         }
670         $post->id = $DB->insert_record('blog_external', $post);
671         return $post;
672     }
674     /**
675      * Get the comment area.
676      *
677      * @param context $context The context.
678      * @param int $itemid The item ID.
679      * @param string $component The component.
680      * @param string $area The area.
681      * @return comment
682      */
683     protected function get_comment_object(context $context, $itemid) {
684         $args = new stdClass();
685         $args->context = $context;
686         $args->course = get_course(SITEID);
687         $args->area = 'format_blog';
688         $args->itemid = $itemid;
689         $args->component = 'blog';
690         $comment = new comment($args);
691         $comment->set_post_permission(true);
692         return $comment;
693     }