2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Data provider tests.
20 * @package logstore_standard
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
27 defined('MOODLE_INTERNAL') || die();
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_standard\privacy\provider;
37 require_once(__DIR__ . '/fixtures/event.php');
40 * Data provider testcase class.
42 * @package logstore_standard
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
48 class logstore_standard_privacy_testcase extends provider_testcase {
50 public function setUp() {
51 $this->resetAfterTest();
52 $this->preventResetByRollback(); // Logging waits till the transaction gets committed.
55 public function test_get_contexts_for_userid() {
56 $admin = \core_user::get_user(2);
57 $u1 = $this->getDataGenerator()->create_user();
58 $u2 = $this->getDataGenerator()->create_user();
59 $u3 = $this->getDataGenerator()->create_user();
61 $c1 = $this->getDataGenerator()->create_course();
62 $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
63 $c2 = $this->getDataGenerator()->create_course();
64 $cm2 = $this->getDataGenerator()->create_module('url', ['course' => $c2]);
66 $sysctx = context_system::instance();
67 $c1ctx = context_course::instance($c1->id);
68 $c2ctx = context_course::instance($c2->id);
69 $cm1ctx = context_module::instance($cm1->cmid);
70 $cm2ctx = context_module::instance($cm2->cmid);
72 $this->enable_logging();
73 $manager = get_log_manager(true);
75 // User 1 is the author.
77 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), []);
78 $e = \logstore_standard\event\unittest_executed::create(['context' => $cm1ctx]);
80 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]);
82 // User 2 is the related user.
84 $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), []);
85 $e = \logstore_standard\event\unittest_executed::create(['context' => $cm2ctx, 'relateduserid' => $u2->id]);
87 $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), [$cm2ctx]);
89 // Admin user is the real user.
90 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), []);
91 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), []);
92 $this->setAdminUser();
93 \core\session\manager::loginas($u3->id, $sysctx);
94 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
96 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx]);
97 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx]);
99 // By admin user masquerading u1 related to u3.
100 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]);
101 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx]);
102 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx]);
103 $this->setAdminUser();
104 \core\session\manager::loginas($u1->id, context_system::instance());
105 $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u3->id]);
107 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$sysctx, $cm1ctx, $c2ctx]);
108 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx, $c2ctx]);
109 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx, $c2ctx]);
112 public function test_delete_data_for_user() {
114 $u1 = $this->getDataGenerator()->create_user();
115 $u2 = $this->getDataGenerator()->create_user();
116 $c1 = $this->getDataGenerator()->create_course();
117 $c2 = $this->getDataGenerator()->create_course();
118 $sysctx = context_system::instance();
119 $c1ctx = context_course::instance($c1->id);
120 $c2ctx = context_course::instance($c2->id);
122 $this->enable_logging();
123 $manager = get_log_manager(true);
125 // User 1 is the author.
127 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
129 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
131 $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
134 // User 2 is the author.
136 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
138 $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
141 // Confirm data present.
142 $this->assertTrue($DB->record_exists('logstore_standard_log', ['userid' => $u1->id, 'contextid' => $c1ctx->id]));
143 $this->assertEquals(3, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
144 $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
146 // Delete all the things!
147 provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_standard', [$c1ctx->id]));
148 $this->assertFalse($DB->record_exists('logstore_standard_log', ['userid' => $u1->id, 'contextid' => $c1ctx->id]));
149 $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
150 $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
153 public function test_delete_data_for_all_users_in_context() {
155 $u1 = $this->getDataGenerator()->create_user();
156 $u2 = $this->getDataGenerator()->create_user();
157 $c1 = $this->getDataGenerator()->create_course();
158 $c2 = $this->getDataGenerator()->create_course();
159 $sysctx = context_system::instance();
160 $c1ctx = context_course::instance($c1->id);
161 $c2ctx = context_course::instance($c2->id);
163 $this->enable_logging();
164 $manager = get_log_manager(true);
166 // User 1 is the author.
168 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
170 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
172 $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
175 // User 2 is the author.
177 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
179 $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
182 // Confirm data present.
183 $this->assertTrue($DB->record_exists('logstore_standard_log', ['contextid' => $c1ctx->id]));
184 $this->assertEquals(3, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
185 $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
187 // Delete all the things!
188 provider::delete_data_for_all_users_in_context($c1ctx);
189 $this->assertFalse($DB->record_exists('logstore_standard_log', ['contextid' => $c1ctx->id]));
190 $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
191 $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
194 public function test_export_data_for_user() {
195 $admin = \core_user::get_user(2);
196 $u1 = $this->getDataGenerator()->create_user();
197 $u2 = $this->getDataGenerator()->create_user();
198 $u3 = $this->getDataGenerator()->create_user();
199 $u4 = $this->getDataGenerator()->create_user();
200 $c1 = $this->getDataGenerator()->create_course();
201 $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
202 $c2 = $this->getDataGenerator()->create_course();
203 $cm2 = $this->getDataGenerator()->create_module('url', ['course' => $c2]);
204 $sysctx = context_system::instance();
205 $c1ctx = context_course::instance($c1->id);
206 $c2ctx = context_course::instance($c2->id);
207 $cm1ctx = context_module::instance($cm1->cmid);
208 $cm2ctx = context_module::instance($cm2->cmid);
210 $path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_standard')];
211 $this->enable_logging();
212 $manager = get_log_manager(true);
214 // User 1 is the author.
216 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx, 'other' => ['i' => 0]]);
219 // User 2 is related.
221 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx, 'relateduserid' => $u2->id,
222 'other' => ['i' => 1]]);
225 // Admin user masquerades u3, which is related to u4.
226 $this->setAdminUser();
227 \core\session\manager::loginas($u3->id, $sysctx);
228 $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx, 'relateduserid' => $u4->id,
229 'other' => ['i' => 2]]);
232 // Confirm data present for u1.
233 provider::export_user_data(new approved_contextlist($u1, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
234 $data = writer::with_context($c2ctx)->get_data($path);
235 $this->assertEmpty($data);
236 $data = writer::with_context($c1ctx)->get_data($path);
237 $this->assertCount(1, $data->logs);
238 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
239 $this->assertSame(0, $data->logs[0]['other']['i']);
241 // Confirm data present for u2.
243 provider::export_user_data(new approved_contextlist($u2, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
244 $data = writer::with_context($c2ctx)->get_data($path);
245 $this->assertEmpty($data);
246 $data = writer::with_context($c1ctx)->get_data($path);
247 $this->assertCount(1, $data->logs);
248 $this->assertEquals(transform::yesno(false), $data->logs[0]['author_of_the_action_was_you']);
249 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
250 $this->assertSame(1, $data->logs[0]['other']['i']);
252 // Confirm data present for u3.
254 provider::export_user_data(new approved_contextlist($u3, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
255 $data = writer::with_context($c2ctx)->get_data($path);
256 $this->assertEmpty($data);
257 $data = writer::with_context($c1ctx)->get_data($path);
258 $this->assertCount(1, $data->logs);
259 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
260 $this->assertEquals(transform::yesno(false), $data->logs[0]['related_user_was_you']);
261 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
262 $this->assertEquals(transform::yesno(false), $data->logs[0]['masquerading_user_was_you']);
263 $this->assertSame(2, $data->logs[0]['other']['i']);
265 // Confirm data present for u4.
267 provider::export_user_data(new approved_contextlist($u4, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
268 $data = writer::with_context($c2ctx)->get_data($path);
269 $this->assertEmpty($data);
270 $data = writer::with_context($c1ctx)->get_data($path);
271 $this->assertCount(1, $data->logs);
272 $this->assertEquals(transform::yesno(false), $data->logs[0]['author_of_the_action_was_you']);
273 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
274 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
275 $this->assertEquals(transform::yesno(false), $data->logs[0]['masquerading_user_was_you']);
276 $this->assertSame(2, $data->logs[0]['other']['i']);
278 // Add anonymous events.
280 $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u2->id,
281 'anonymous' => true]);
283 $this->setAdminUser();
284 \core\session\manager::loginas($u3->id, $sysctx);
285 $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u4->id,
286 'anonymous' => true]);
289 // Confirm data present for u1.
290 provider::export_user_data(new approved_contextlist($u1, 'logstore_standard', [$c2ctx->id]));
291 $data = writer::with_context($c2ctx)->get_data($path);
292 $this->assertCount(1, $data->logs);
293 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
294 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
296 // Confirm data present for u2.
298 provider::export_user_data(new approved_contextlist($u2, 'logstore_standard', [$c2ctx->id]));
299 $data = writer::with_context($c2ctx)->get_data($path);
300 $this->assertCount(1, $data->logs);
301 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
302 $this->assertArrayNotHasKey('author_of_the_action_was_you', $data->logs[0]);
303 $this->assertArrayNotHasKey('authorid', $data->logs[0]);
304 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
306 // Confirm data present for u3.
308 provider::export_user_data(new approved_contextlist($u3, 'logstore_standard', [$c2ctx->id]));
309 $data = writer::with_context($c2ctx)->get_data($path);
310 $this->assertCount(1, $data->logs);
311 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
312 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
313 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
314 $this->assertArrayNotHasKey('masquerading_user_was_you', $data->logs[0]);
315 $this->assertArrayNotHasKey('masqueradinguserid', $data->logs[0]);
317 // Confirm data present for u4.
319 provider::export_user_data(new approved_contextlist($u4, 'logstore_standard', [$c2ctx->id]));
320 $data = writer::with_context($c2ctx)->get_data($path);
321 $this->assertCount(1, $data->logs);
322 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
323 $this->assertArrayNotHasKey('author_of_the_action_was_you', $data->logs[0]);
324 $this->assertArrayNotHasKey('authorid', $data->logs[0]);
325 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
326 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
327 $this->assertArrayNotHasKey('masquerading_user_was_you', $data->logs[0]);
328 $this->assertArrayNotHasKey('masqueradinguserid', $data->logs[0]);
332 * Assert the content of a context list.
334 * @param contextlist $contextlist The collection.
335 * @param array $expected List of expected contexts or IDs.
338 protected function assert_contextlist_equals($contextlist, array $expected) {
339 $expectedids = array_map(function($context) {
340 if (is_object($context)) {
345 $contextids = array_map('intval', $contextlist->get_contextids());
348 $this->assertEquals($expectedids, $contextids);
356 protected function enable_logging() {
357 set_config('enabled_stores', 'logstore_standard', 'tool_log');
358 set_config('buffersize', 0, 'logstore_standard');
359 set_config('logguests', 1, 'logstore_standard');
363 * Get the contextlist for a user.
365 * @param object $user The user.
366 * @return contextlist
368 protected function get_contextlist_for_user($user) {
369 $contextlist = new contextlist();
370 provider::add_contexts_for_userid($contextlist, $user->id);