MDL-63666 logging: Add support for removal of context users.
[moodle.git] / admin / tool / log / store / legacy / 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    logstore_legacy
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\contextlist;
32 use core_privacy\local\request\approved_contextlist;
33 use core_privacy\local\request\transform;
34 use core_privacy\local\request\writer;
35 use logstore_legacy\privacy\provider;
36 use logstore_legacy\event\unittest_executed;
38 require_once(__DIR__ . '/fixtures/event.php');
40 /**
41  * Data provider testcase class.
42  *
43  * @package    logstore_legacy
44  * @category   test
45  * @copyright  2018 Frédéric Massart
46  * @author     Frédéric Massart <fred@branchup.tech>
47  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
48  */
49 class logstore_legacy_privacy_testcase extends provider_testcase {
51     public function setUp() {
52         $this->resetAfterTest();
53     }
55     public function test_get_contexts_for_userid() {
56         $u1 = $this->getDataGenerator()->create_user();
57         $u2 = $this->getDataGenerator()->create_user();
58         $u3 = $this->getDataGenerator()->create_user();
59         $c1 = $this->getDataGenerator()->create_course();
60         $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
61         $sysctx = context_system::instance();
62         $c1ctx = context_course::instance($c1->id);
63         $cm1ctx = context_module::instance($cm1->cmid);
65         $this->enable_logging();
66         $manager = get_log_manager(true);
68         // User 1 is the author.
69         $this->setUser($u1);
70         $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), []);
71         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
72         $e->trigger();
73         $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]);
75         // User 2 is the author.
76         $this->setUser($u2);
77         $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), []);
78         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
79         $e->trigger();
80         $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), [$cm1ctx]);
82         // User 3 is the author.
83         $this->setUser($u3);
84         $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), []);
85         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 3]]);
86         $e->trigger();
87         $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx]);
88     }
90     /**
91      * Test returning user IDs for a given context.
92      */
93     public function test_add_userids_for_context() {
94         $u1 = $this->getDataGenerator()->create_user();
95         $u2 = $this->getDataGenerator()->create_user();
96         $u3 = $this->getDataGenerator()->create_user();
97         $course = $this->getDataGenerator()->create_course();
98         $module = $this->getDataGenerator()->create_module('url', ['course' => $course]);
99         $sysctx = context_system::instance();
100         $c1ctx = context_course::instance($course->id);
101         $cm1ctx = context_module::instance($module->cmid);
103         $userctx = context_user::instance($u1->id);
105         $this->enable_logging();
106         $manager = get_log_manager(true);
108         $this->setUser($u1);
109         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 1]]);
110         $e->trigger();
111         $this->setUser($u2);
112         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 2]]);
113         $e->trigger();
114         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 3]]);
115         $e->trigger();
116         $this->setUser($u3);
117         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 4]]);
118         $e->trigger();
119         $this->setUser($u1);
120         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 5]]);
121         $e->trigger();
122         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 6]]);
123         $e->trigger();
124         $this->setUser($u2);
125         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 7]]);
126         $e->trigger();
127         $this->setUser($u3);
128         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 8]]);
129         $e->trigger();
131         // Start with system and check that each of the contexts returns what we expected.
132         $userlist = new \core_privacy\local\request\userlist($sysctx, 'logstore_legacy');
133         provider::add_userids_for_context($userlist);
134         $systemuserids = $userlist->get_userids();
135         $this->assertCount(2, $systemuserids);
136         $this->assertNotFalse(array_search($u1->id, $systemuserids));
137         $this->assertNotFalse(array_search($u2->id, $systemuserids));
138         // Check the course context.
139         $userlist = new \core_privacy\local\request\userlist($c1ctx, 'logstore_legacy');
140         provider::add_userids_for_context($userlist);
141         $courseuserids = $userlist->get_userids();
142         $this->assertCount(2, $courseuserids);
143         $this->assertNotFalse(array_search($u1->id, $courseuserids));
144         $this->assertNotFalse(array_search($u3->id, $courseuserids));
145         // Check the module context.
146         $userlist = new \core_privacy\local\request\userlist($cm1ctx, 'logstore_legacy');
147         provider::add_userids_for_context($userlist);
148         $moduleuserids = $userlist->get_userids();
149         $this->assertCount(3, $moduleuserids);
150         $this->assertNotFalse(array_search($u1->id, $moduleuserids));
151         $this->assertNotFalse(array_search($u2->id, $moduleuserids));
152         $this->assertNotFalse(array_search($u3->id, $moduleuserids));
153     }
155     public function test_delete_data_for_user() {
156         global $DB;
158         $u1 = $this->getDataGenerator()->create_user();
159         $u2 = $this->getDataGenerator()->create_user();
160         $u3 = $this->getDataGenerator()->create_user();
161         $c1 = $this->getDataGenerator()->create_course();
162         $c2 = $this->getDataGenerator()->create_course();
163         $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
164         $sysctx = context_system::instance();
165         $c1ctx = context_course::instance($c1->id);
166         $c2ctx = context_course::instance($c2->id);
167         $cm1ctx = context_module::instance($cm1->cmid);
169         $this->enable_logging();
170         $manager = get_log_manager(true);
172         // User 1 is the author.
173         $this->setUser($u1);
174         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
175         $e->trigger();
176         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
177         $e->trigger();
178         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 3]]);
179         $e->trigger();
180         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 4]]);
181         $e->trigger();
183         // User 2 is the author.
184         $this->setUser($u2);
185         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 5]]);
186         $e->trigger();
187         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 6]]);
188         $e->trigger();
189         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 7]]);
190         $e->trigger();
192         // Assert what we have.
193         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
194         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
195         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
196         $this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
197         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
199         // Delete other context.
200         provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$c2ctx->id]));
201         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
202         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
203         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
204         $this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
205         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
207         // Delete system.
208         provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$sysctx->id]));
209         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
210         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
211         $this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
212         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u1->id]));
213         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
215         // Delete course.
216         provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$c1ctx->id]));
217         $this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
218         $this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
219         $this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
220         $this->assertEquals(2, $DB->count_records('log', ['userid' => $u1->id]));
221         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
223         // Delete course.
224         provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$cm1ctx->id]));
225         $this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
226         $this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
227         $this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
228         $this->assertEquals(0, $DB->count_records('log', ['userid' => $u1->id]));
229         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
230     }
232     public function test_delete_data_for_all_users_in_context() {
233         global $DB;
235         $u1 = $this->getDataGenerator()->create_user();
236         $u2 = $this->getDataGenerator()->create_user();
237         $u3 = $this->getDataGenerator()->create_user();
238         $c1 = $this->getDataGenerator()->create_course();
239         $c2 = $this->getDataGenerator()->create_course();
240         $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
241         $sysctx = context_system::instance();
242         $c1ctx = context_course::instance($c1->id);
243         $c2ctx = context_course::instance($c2->id);
244         $cm1ctx = context_module::instance($cm1->cmid);
246         $this->enable_logging();
247         $manager = get_log_manager(true);
249         // User 1 is the author.
250         $this->setUser($u1);
251         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
252         $e->trigger();
253         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
254         $e->trigger();
255         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 3]]);
256         $e->trigger();
257         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 4]]);
258         $e->trigger();
260         // User 2 is the author.
261         $this->setUser($u2);
262         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 5]]);
263         $e->trigger();
264         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 6]]);
265         $e->trigger();
266         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 7]]);
267         $e->trigger();
269         // Assert what we have.
270         $this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
271         $this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
272         $this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
273         $this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
274         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
276         // Delete other context.
277         provider::delete_data_for_all_users_in_context($c2ctx);
278         $this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
279         $this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
280         $this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
281         $this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
282         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
284         // Delete system.
285         provider::delete_data_for_all_users_in_context($sysctx);
286         $this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
287         $this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
288         $this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
289         $this->assertEquals(3, $DB->count_records('log', ['userid' => $u1->id]));
290         $this->assertEquals(2, $DB->count_records('log', ['userid' => $u2->id]));
292         // Delete course.
293         provider::delete_data_for_all_users_in_context($c1ctx);
294         $this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
295         $this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
296         $this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
297         $this->assertEquals(2, $DB->count_records('log', ['userid' => $u1->id]));
298         $this->assertEquals(1, $DB->count_records('log', ['userid' => $u2->id]));
300         // Delete course.
301         provider::delete_data_for_all_users_in_context($cm1ctx);
302         $this->assertFalse($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
303         $this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
304         $this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
305         $this->assertEquals(0, $DB->count_records('log', ['userid' => $u1->id]));
306         $this->assertEquals(0, $DB->count_records('log', ['userid' => $u2->id]));
307     }
309     /**
310      * Test the deletion of data for users in a context.
311      */
312     public function test_delete_data_for_all_users() {
313         global $DB;
315         $u1 = $this->getDataGenerator()->create_user();
316         $u2 = $this->getDataGenerator()->create_user();
317         $u3 = $this->getDataGenerator()->create_user();
318         $course = $this->getDataGenerator()->create_course();
319         $module = $this->getDataGenerator()->create_module('url', ['course' => $course]);
320         $sysctx = context_system::instance();
321         $c1ctx = context_course::instance($course->id);
322         $cm1ctx = context_module::instance($module->cmid);
324         $userctx = context_user::instance($u1->id);
326         $this->enable_logging();
327         $manager = get_log_manager(true);
329         $this->setUser($u1);
330         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 1]]);
331         $e->trigger();
332         $this->setUser($u2);
333         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 2]]);
334         $e->trigger();
335         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 3]]);
336         $e->trigger();
337         $this->setUser($u3);
338         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 4]]);
339         $e->trigger();
340         $this->setUser($u1);
341         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 5]]);
342         $e->trigger();
343         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 6]]);
344         $e->trigger();
345         $this->setUser($u2);
346         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 7]]);
347         $e->trigger();
348         $this->setUser($u3);
349         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 8]]);
350         $e->trigger();
352         // System context deleting one user.
353         $this->assertEquals(3, $DB->count_records('log', ['cmid' => 0, 'course' => 0]));
354         $userlist = new \core_privacy\local\request\approved_userlist($sysctx, 'logstore_legacy', [$u2->id]);
355         provider::delete_data_for_all_users($userlist);
356         $this->assertEquals(1, $DB->count_records('log', ['cmid' => 0, 'course' => 0]));
358         // Course context deleting one user.
359         $this->assertEquals(2, $DB->count_records('log', ['cmid' => 0, 'course' => $course->id]));
360         $userlist = new \core_privacy\local\request\approved_userlist($c1ctx, 'logstore_legacy', [$u1->id]);
361         provider::delete_data_for_all_users($userlist);
362         $this->assertEquals(1, $DB->count_records('log', ['cmid' => 0, 'course' => $course->id]));
364         // Module context deleting two users.
365         $this->assertEquals(3, $DB->count_records('log', ['cmid' => $module->cmid, 'course' => $course->id]));
366         $userlist = new \core_privacy\local\request\approved_userlist($cm1ctx, 'logstore_legacy', [$u1->id, $u3->id]);
367         provider::delete_data_for_all_users($userlist);
368         $this->assertEquals(1, $DB->count_records('log', ['cmid' => $module->cmid, 'course' => $course->id]));
369     }
371     public function test_export_data_for_user() {
372         global $DB;
374         $u1 = $this->getDataGenerator()->create_user();
375         $u2 = $this->getDataGenerator()->create_user();
376         $u3 = $this->getDataGenerator()->create_user();
377         $c1 = $this->getDataGenerator()->create_course();
378         $c2 = $this->getDataGenerator()->create_course();
379         $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
380         $sysctx = context_system::instance();
381         $c1ctx = context_course::instance($c1->id);
382         $c2ctx = context_course::instance($c2->id);
383         $cm1ctx = context_module::instance($cm1->cmid);
385         $this->enable_logging();
386         $manager = get_log_manager(true);
387         $path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_legacy')];
389         // User 1 is the author.
390         $this->setUser($u1);
391         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
392         $e->trigger();
393         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
394         $e->trigger();
395         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 3]]);
396         $e->trigger();
397         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 4]]);
398         $e->trigger();
400         // User 2 is the author.
401         $this->setUser($u2);
402         $e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 5]]);
403         $e->trigger();
404         $e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 6]]);
405         $e->trigger();
406         $e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 7]]);
407         $e->trigger();
409         // Test export.
410         provider::export_user_data(new approved_contextlist($u1, 'logstore_legacy', [$cm1ctx->id]));
411         $data = writer::with_context($c1ctx)->get_data($path);
412         $this->assertEmpty($data);
413         $data = writer::with_context($cm1ctx)->get_data($path);
414         $this->assertCount(2, $data->logs);
416         writer::reset();
417         provider::export_user_data(new approved_contextlist($u1, 'logstore_legacy', [$c1ctx->id]));
418         $data = writer::with_context($cm1ctx)->get_data($path);
419         $this->assertEmpty($data);
420         $data = writer::with_context($c1ctx)->get_data($path);
421         $this->assertCount(1, $data->logs);
423         writer::reset();
424         provider::export_user_data(new approved_contextlist($u1, 'logstore_legacy', [$sysctx->id]));
425         $data = writer::with_context($sysctx)->get_data($path);
426         $this->assertCount(1, $data->logs);
427     }
429     /**
430      * Assert the content of a context list.
431      *
432      * @param contextlist $contextlist The collection.
433      * @param array $expected List of expected contexts or IDs.
434      * @return void
435      */
436     protected function assert_contextlist_equals($contextlist, array $expected) {
437         $expectedids = array_map(function($context) {
438             if (is_object($context)) {
439                 return $context->id;
440             }
441             return $context;
442         }, $expected);
443         $contextids = array_map('intval', $contextlist->get_contextids());
444         sort($contextids);
445         sort($expectedids);
446         $this->assertEquals($expectedids, $contextids);
447     }
449     /**
450      * Enable logging.
451      *
452      * @return void
453      */
454     protected function enable_logging() {
455         set_config('enabled_stores', 'logstore_legacy', 'tool_log');
456         set_config('loglegacy', 1, 'logstore_legacy');
457         get_log_manager(true);
458     }
460     /**
461      * Get the contextlist for a user.
462      *
463      * @param object $user The user.
464      * @return contextlist
465      */
466     protected function get_contextlist_for_user($user) {
467         $contextlist = new contextlist();
468         provider::add_contexts_for_userid($contextlist, $user->id);
469         return $contextlist;
470     }