MDL-62962 tool_dataprivacy: Move user generation within the test
[moodle.git] / admin / tool / dataprivacy / tests / api_test.php
CommitLineData
5efc1f9e
DM
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 * API tests.
19 *
20 * @package tool_dataprivacy
21 * @copyright 2018 Jun Pataleta
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25use core\invalid_persistent_exception;
26use core\task\manager;
27use tool_dataprivacy\context_instance;
28use tool_dataprivacy\api;
29use tool_dataprivacy\data_registry;
30use tool_dataprivacy\expired_context;
31use tool_dataprivacy\data_request;
4c72ffa5 32use tool_dataprivacy\local\helper;
5efc1f9e
DM
33use tool_dataprivacy\task\initiate_data_request_task;
34use tool_dataprivacy\task\process_data_request_task;
35
36defined('MOODLE_INTERNAL') || die();
37global $CFG;
38
39/**
40 * API tests.
41 *
42 * @package tool_dataprivacy
43 * @copyright 2018 Jun Pataleta
44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 */
46class tool_dataprivacy_api_testcase extends advanced_testcase {
47
48 /**
49 * setUp.
50 */
51 public function setUp() {
52 $this->resetAfterTest();
53 }
54
55 /**
56 * Test for api::update_request_status().
57 */
58 public function test_update_request_status() {
59 $generator = new testing_data_generator();
60 $s1 = $generator->create_user();
7bdb9d87 61 $this->setUser($s1);
5efc1f9e
DM
62
63 // Create the sample data request.
64 $datarequest = api::create_data_request($s1->id, api::DATAREQUEST_TYPE_EXPORT);
65
66 $requestid = $datarequest->get('id');
67
68 // Update with a valid status.
69 $result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_COMPLETE);
70 $this->assertTrue($result);
71
72 // Fetch the request record again.
73 $datarequest = new data_request($requestid);
74 $this->assertEquals(api::DATAREQUEST_STATUS_COMPLETE, $datarequest->get('status'));
75
76 // Update with an invalid status.
77 $this->expectException(invalid_persistent_exception::class);
78 api::update_request_status($requestid, -1);
79 }
80
81 /**
82 * Test for api::get_site_dpos() when there are no users with the DPO role.
83 */
84 public function test_get_site_dpos_no_dpos() {
85 $admin = get_admin();
86
87 $dpos = api::get_site_dpos();
88 $this->assertCount(1, $dpos);
89 $dpo = reset($dpos);
90 $this->assertEquals($admin->id, $dpo->id);
91 }
92
93 /**
94 * Test for api::get_site_dpos() when there are no users with the DPO role.
95 */
96 public function test_get_site_dpos() {
97 global $DB;
98 $generator = new testing_data_generator();
99 $u1 = $generator->create_user();
100 $u2 = $generator->create_user();
101
102 $context = context_system::instance();
103
104 // Give the manager role with the capability to manage data requests.
105 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
106 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true);
107 // Assign u1 as a manager.
108 role_assign($managerroleid, $u1->id, $context->id);
109
110 // Give the editing teacher role with the capability to manage data requests.
111 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher'));
112 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $editingteacherroleid, $context->id, true);
113 // Assign u1 as an editing teacher as well.
114 role_assign($editingteacherroleid, $u1->id, $context->id);
115 // Assign u2 as an editing teacher.
116 role_assign($editingteacherroleid, $u2->id, $context->id);
117
118 // Only map the manager role to the DPO role.
119 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
120
121 $dpos = api::get_site_dpos();
122 $this->assertCount(1, $dpos);
123 $dpo = reset($dpos);
124 $this->assertEquals($u1->id, $dpo->id);
125 }
126
127 /**
128 * Test for api::approve_data_request().
129 */
130 public function test_approve_data_request() {
131 global $DB;
132
133 $generator = new testing_data_generator();
134 $s1 = $generator->create_user();
135 $u1 = $generator->create_user();
136
137 $context = context_system::instance();
138
139 // Manager role.
140 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
141 // Give the manager role with the capability to manage data requests.
142 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true);
143 // Assign u1 as a manager.
144 role_assign($managerroleid, $u1->id, $context->id);
145
146 // Map the manager role to the DPO role.
147 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
148
149 // Create the sample data request.
7bdb9d87 150 $this->setUser($s1);
5efc1f9e
DM
151 $datarequest = api::create_data_request($s1->id, api::DATAREQUEST_TYPE_EXPORT);
152 $requestid = $datarequest->get('id');
153
154 // Make this ready for approval.
155 api::update_request_status($requestid, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
156
157 $this->setUser($u1);
158 $result = api::approve_data_request($requestid);
159 $this->assertTrue($result);
160 $datarequest = new data_request($requestid);
161 $this->assertEquals($u1->id, $datarequest->get('dpo'));
162 $this->assertEquals(api::DATAREQUEST_STATUS_APPROVED, $datarequest->get('status'));
163
164 // Test adhoc task creation.
165 $adhoctasks = manager::get_adhoc_tasks(process_data_request_task::class);
166 $this->assertCount(1, $adhoctasks);
167 }
168
169 /**
170 * Test for api::approve_data_request() with the request not yet waiting for approval.
171 */
172 public function test_approve_data_request_not_yet_ready() {
173 global $DB;
174
175 $generator = new testing_data_generator();
176 $s1 = $generator->create_user();
177 $u1 = $generator->create_user();
178
179 $context = context_system::instance();
180
181 // Manager role.
182 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
183 // Give the manager role with the capability to manage data requests.
184 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true);
185 // Assign u1 as a manager.
186 role_assign($managerroleid, $u1->id, $context->id);
187
188 // Map the manager role to the DPO role.
189 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
190
191 // Create the sample data request.
7bdb9d87 192 $this->setUser($s1);
5efc1f9e
DM
193 $datarequest = api::create_data_request($s1->id, api::DATAREQUEST_TYPE_EXPORT);
194 $requestid = $datarequest->get('id');
195
196 $this->setUser($u1);
197 $this->expectException(moodle_exception::class);
198 api::approve_data_request($requestid);
199 }
200
201 /**
202 * Test for api::approve_data_request() when called by a user who doesn't have the DPO role.
203 */
204 public function test_approve_data_request_non_dpo_user() {
205 $generator = new testing_data_generator();
206 $student = $generator->create_user();
207 $teacher = $generator->create_user();
208
209 // Create the sample data request.
7bdb9d87 210 $this->setUser($student);
5efc1f9e
DM
211 $datarequest = api::create_data_request($student->id, api::DATAREQUEST_TYPE_EXPORT);
212
213 $requestid = $datarequest->get('id');
214
215 // Login as a user without DPO role.
216 $this->setUser($teacher);
217 $this->expectException(required_capability_exception::class);
218 api::approve_data_request($requestid);
219 }
220
221 /**
222 * Test for api::can_contact_dpo()
223 */
224 public function test_can_contact_dpo() {
ba5b59c0 225 // Default ('contactdataprotectionofficer' is disabled by default).
5efc1f9e
DM
226 $this->assertFalse(api::can_contact_dpo());
227
ba5b59c0 228 // Enable.
5efc1f9e
DM
229 set_config('contactdataprotectionofficer', 1, 'tool_dataprivacy');
230 $this->assertTrue(api::can_contact_dpo());
ba5b59c0
JP
231
232 // Disable again.
233 set_config('contactdataprotectionofficer', 0, 'tool_dataprivacy');
234 $this->assertFalse(api::can_contact_dpo());
5efc1f9e
DM
235 }
236
237 /**
238 * Test for api::can_manage_data_requests()
239 */
240 public function test_can_manage_data_requests() {
241 global $DB;
242
243 // No configured site DPOs yet.
244 $admin = get_admin();
245 $this->assertTrue(api::can_manage_data_requests($admin->id));
246
247 $generator = new testing_data_generator();
248 $dpo = $generator->create_user();
249 $nondpocapable = $generator->create_user();
250 $nondpoincapable = $generator->create_user();
251
252 $context = context_system::instance();
253
254 // Manager role.
255 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
256 // Give the manager role with the capability to manage data requests.
257 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true);
258 // Assign u1 as a manager.
259 role_assign($managerroleid, $dpo->id, $context->id);
260
261 // Editing teacher role.
262 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher'));
263 // Give the editing teacher role with the capability to manage data requests.
264 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true);
265 // Assign u2 as an editing teacher.
266 role_assign($editingteacherroleid, $nondpocapable->id, $context->id);
267
268 // Map only the manager role to the DPO role.
269 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
270
271 // User with capability and has DPO role.
272 $this->assertTrue(api::can_manage_data_requests($dpo->id));
273 // User with capability but has no DPO role.
274 $this->assertFalse(api::can_manage_data_requests($nondpocapable->id));
275 // User without the capability and has no DPO role.
276 $this->assertFalse(api::can_manage_data_requests($nondpoincapable->id));
277 }
278
279 /**
280 * Test for api::create_data_request()
281 */
282 public function test_create_data_request() {
283 $generator = new testing_data_generator();
284 $user = $generator->create_user();
285 $comment = 'sample comment';
286
287 // Login as user.
288 $this->setUser($user->id);
289
290 // Test data request creation.
291 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment);
292 $this->assertEquals($user->id, $datarequest->get('userid'));
293 $this->assertEquals($user->id, $datarequest->get('requestedby'));
7bdb9d87
JP
294 $this->assertEquals(0, $datarequest->get('dpo'));
295 $this->assertEquals(api::DATAREQUEST_TYPE_EXPORT, $datarequest->get('type'));
296 $this->assertEquals(api::DATAREQUEST_STATUS_PENDING, $datarequest->get('status'));
297 $this->assertEquals($comment, $datarequest->get('comments'));
298
299 // Test adhoc task creation.
300 $adhoctasks = manager::get_adhoc_tasks(initiate_data_request_task::class);
301 $this->assertCount(1, $adhoctasks);
302 }
303
304 /**
305 * Test for api::create_data_request() made by DPO.
306 */
307 public function test_create_data_request_by_dpo() {
308 global $USER;
309
310 $generator = new testing_data_generator();
311 $user = $generator->create_user();
312 $comment = 'sample comment';
313
314 // Login as DPO (Admin is DPO by default).
315 $this->setAdminUser();
316
317 // Test data request creation.
318 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment);
319 $this->assertEquals($user->id, $datarequest->get('userid'));
320 $this->assertEquals($USER->id, $datarequest->get('requestedby'));
321 $this->assertEquals($USER->id, $datarequest->get('dpo'));
322 $this->assertEquals(api::DATAREQUEST_TYPE_EXPORT, $datarequest->get('type'));
323 $this->assertEquals(api::DATAREQUEST_STATUS_PENDING, $datarequest->get('status'));
324 $this->assertEquals($comment, $datarequest->get('comments'));
325
326 // Test adhoc task creation.
327 $adhoctasks = manager::get_adhoc_tasks(initiate_data_request_task::class);
328 $this->assertCount(1, $adhoctasks);
329 }
330
331 /**
332 * Test for api::create_data_request() made by a parent.
333 */
334 public function test_create_data_request_by_parent() {
335 global $DB;
336
337 $generator = new testing_data_generator();
338 $user = $generator->create_user();
339 $parent = $generator->create_user();
340 $comment = 'sample comment';
341
342 // Get the teacher role pretend it's the parent roles ;).
343 $systemcontext = context_system::instance();
344 $usercontext = context_user::instance($user->id);
345 $parentroleid = $DB->get_field('role', 'id', array('shortname' => 'teacher'));
346 // Give the manager role with the capability to manage data requests.
347 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentroleid, $systemcontext->id, true);
348 // Assign the parent to user.
349 role_assign($parentroleid, $parent->id, $usercontext->id);
350
351 // Login as the user's parent.
352 $this->setUser($parent);
353
354 // Test data request creation.
355 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment);
356 $this->assertEquals($user->id, $datarequest->get('userid'));
357 $this->assertEquals($parent->id, $datarequest->get('requestedby'));
358 $this->assertEquals(0, $datarequest->get('dpo'));
5efc1f9e
DM
359 $this->assertEquals(api::DATAREQUEST_TYPE_EXPORT, $datarequest->get('type'));
360 $this->assertEquals(api::DATAREQUEST_STATUS_PENDING, $datarequest->get('status'));
361 $this->assertEquals($comment, $datarequest->get('comments'));
362
363 // Test adhoc task creation.
364 $adhoctasks = manager::get_adhoc_tasks(initiate_data_request_task::class);
365 $this->assertCount(1, $adhoctasks);
366 }
367
368 /**
369 * Test for api::deny_data_request()
370 */
371 public function test_deny_data_request() {
372 $generator = new testing_data_generator();
373 $user = $generator->create_user();
374 $comment = 'sample comment';
375
376 // Login as user.
377 $this->setUser($user->id);
378
379 // Test data request creation.
380 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment);
381
382 // Login as the admin (default DPO when no one is set).
383 $this->setAdminUser();
384
385 // Make this ready for approval.
386 api::update_request_status($datarequest->get('id'), api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
387
388 // Deny the data request.
389 $result = api::deny_data_request($datarequest->get('id'));
390 $this->assertTrue($result);
391 }
392
393 /**
394 * Test for api::deny_data_request()
395 */
396 public function test_deny_data_request_without_permissions() {
397 $generator = new testing_data_generator();
398 $user = $generator->create_user();
399 $comment = 'sample comment';
400
401 // Login as user.
402 $this->setUser($user->id);
403
404 // Test data request creation.
405 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment);
406
407 // Login as a non-DPO user and try to call deny_data_request.
408 $user2 = $generator->create_user();
409 $this->setUser($user2);
410 $this->expectException(required_capability_exception::class);
411 api::deny_data_request($datarequest->get('id'));
412 }
413
414 /**
4c72ffa5
JP
415 * Data provider for \tool_dataprivacy_api_testcase::test_get_data_requests().
416 *
417 * @return array
5efc1f9e 418 */
4c72ffa5 419 public function get_data_requests_provider() {
4c72ffa5
JP
420 $completeonly = [api::DATAREQUEST_STATUS_COMPLETE];
421 $completeandcancelled = [api::DATAREQUEST_STATUS_COMPLETE, api::DATAREQUEST_STATUS_CANCELLED];
5efc1f9e 422
4c72ffa5
JP
423 return [
424 // Own data requests.
f0ccce9a 425 ['user', false, $completeonly],
4c72ffa5 426 // Non-DPO fetching all requets.
f0ccce9a 427 ['user', true, $completeonly],
4c72ffa5 428 // Admin fetching all completed and cancelled requests.
f0ccce9a 429 ['dpo', true, $completeandcancelled],
4c72ffa5 430 // Admin fetching all completed requests.
f0ccce9a 431 ['dpo', true, $completeonly],
4c72ffa5 432 // Guest fetching all requests.
f0ccce9a 433 ['guest', true, $completeonly],
4c72ffa5
JP
434 ];
435 }
436
437 /**
438 * Test for api::get_data_requests()
439 *
440 * @dataProvider get_data_requests_provider
f0ccce9a 441 * @param string $usertype The type of the user logging in.
4c72ffa5
JP
442 * @param boolean $fetchall Whether to fetch all records.
443 * @param int[] $statuses Status filters.
444 */
f0ccce9a
JP
445 public function test_get_data_requests($usertype, $fetchall, $statuses) {
446 $generator = new testing_data_generator();
447 $user1 = $generator->create_user();
448 $user2 = $generator->create_user();
449 $user3 = $generator->create_user();
450 $user4 = $generator->create_user();
451 $user5 = $generator->create_user();
452 $users = [$user1, $user2, $user3, $user4, $user5];
453
454 switch ($usertype) {
455 case 'user':
456 $loggeduser = $user1;
457 break;
458 case 'dpo':
459 $loggeduser = get_admin();
460 break;
461 case 'guest':
462 $loggeduser = guest_user();
463 break;
464 }
465
4c72ffa5
JP
466 $comment = 'Data %s request comment by user %d';
467 $exportstring = helper::get_shortened_request_type_string(api::DATAREQUEST_TYPE_EXPORT);
468 $deletionstring = helper::get_shortened_request_type_string(api::DATAREQUEST_TYPE_DELETE);
469 // Make a data requests for the users.
470 foreach ($users as $user) {
471 $this->setUser($user);
472 api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, sprintf($comment, $exportstring, $user->id));
473 api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, sprintf($comment, $deletionstring, $user->id));
474 }
475
476 // Log in as the target user.
477 $this->setUser($loggeduser);
478 // Get records count based on the filters.
479 $userid = $loggeduser->id;
480 if ($fetchall) {
481 $userid = 0;
482 }
483 $count = api::get_data_requests_count($userid);
484 if (api::is_site_dpo($loggeduser->id)) {
485 // DPOs should see all the requests.
486 $this->assertEquals(count($users) * 2, $count);
487 } else {
488 if (empty($userid)) {
489 // There should be no data requests for this user available.
490 $this->assertEquals(0, $count);
491 } else {
492 // There should be only one (request with pending status).
493 $this->assertEquals(2, $count);
494 }
495 }
496 // Get data requests.
497 $requests = api::get_data_requests($userid);
498 // The number of requests should match the count.
499 $this->assertCount($count, $requests);
500
501 // Test filtering by status.
502 if ($count && !empty($statuses)) {
503 $filteredcount = api::get_data_requests_count($userid, $statuses);
504 // There should be none as they are all pending.
505 $this->assertEquals(0, $filteredcount);
506 $filteredrequests = api::get_data_requests($userid, $statuses);
507 $this->assertCount($filteredcount, $filteredrequests);
508
509 $statuscounts = [];
510 foreach ($statuses as $stat) {
511 $statuscounts[$stat] = 0;
512 }
513 $numstatus = count($statuses);
514 // Get all requests with status filter and update statuses, randomly.
515 foreach ($requests as $request) {
516 if (rand(0, 1)) {
517 continue;
518 }
519
520 if ($numstatus > 1) {
521 $index = rand(0, $numstatus - 1);
522 $status = $statuses[$index];
523 } else {
524 $status = reset($statuses);
525 }
526 $statuscounts[$status]++;
527 api::update_request_status($request->get('id'), $status);
528 }
529 $total = array_sum($statuscounts);
530 $filteredcount = api::get_data_requests_count($userid, $statuses);
531 $this->assertEquals($total, $filteredcount);
532 $filteredrequests = api::get_data_requests($userid, $statuses);
533 $this->assertCount($filteredcount, $filteredrequests);
534 // Confirm the filtered requests match the status filter(s).
535 foreach ($filteredrequests as $request) {
536 $this->assertContains($request->get('status'), $statuses);
537 }
538
539 if ($numstatus > 1) {
540 // Fetch by individual status to check the numbers match.
541 foreach ($statuses as $status) {
542 $filteredcount = api::get_data_requests_count($userid, [$status]);
543 $this->assertEquals($statuscounts[$status], $filteredcount);
544 $filteredrequests = api::get_data_requests($userid, [$status]);
545 $this->assertCount($filteredcount, $filteredrequests);
546 }
547 }
548 }
5efc1f9e
DM
549 }
550
551 /**
552 * Data provider for test_has_ongoing_request.
553 */
554 public function status_provider() {
555 return [
556 [api::DATAREQUEST_STATUS_PENDING, true],
557 [api::DATAREQUEST_STATUS_PREPROCESSING, true],
558 [api::DATAREQUEST_STATUS_AWAITING_APPROVAL, true],
559 [api::DATAREQUEST_STATUS_APPROVED, true],
560 [api::DATAREQUEST_STATUS_PROCESSING, true],
561 [api::DATAREQUEST_STATUS_COMPLETE, false],
562 [api::DATAREQUEST_STATUS_CANCELLED, false],
563 [api::DATAREQUEST_STATUS_REJECTED, false],
564 ];
565 }
566
567 /**
568 * Test for api::has_ongoing_request()
569 *
570 * @dataProvider status_provider
571 * @param int $status The request status.
572 * @param bool $expected The expected result.
573 */
574 public function test_has_ongoing_request($status, $expected) {
575 $generator = new testing_data_generator();
576 $user1 = $generator->create_user();
577
578 // Make a data request as user 1.
7bdb9d87 579 $this->setUser($user1);
5efc1f9e
DM
580 $request = api::create_data_request($user1->id, api::DATAREQUEST_TYPE_EXPORT);
581 // Set the status.
582 api::update_request_status($request->get('id'), $status);
583
584 // Check if this request is ongoing.
585 $result = api::has_ongoing_request($user1->id, api::DATAREQUEST_TYPE_EXPORT);
586 $this->assertEquals($expected, $result);
587 }
588
589 /**
590 * Test for api::is_active()
591 *
592 * @dataProvider status_provider
593 * @param int $status The request status
594 * @param bool $expected The expected result
595 */
596 public function test_is_active($status, $expected) {
597 // Check if this request is ongoing.
598 $result = api::is_active($status);
599 $this->assertEquals($expected, $result);
600 }
601
602 /**
603 * Test for api::is_site_dpo()
604 */
605 public function test_is_site_dpo() {
606 global $DB;
607
608 // No configured site DPOs yet.
609 $admin = get_admin();
610 $this->assertTrue(api::is_site_dpo($admin->id));
611
612 $generator = new testing_data_generator();
613 $dpo = $generator->create_user();
614 $nondpo = $generator->create_user();
615
616 $context = context_system::instance();
617
618 // Manager role.
619 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
620 // Give the manager role with the capability to manage data requests.
621 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true);
622 // Assign u1 as a manager.
623 role_assign($managerroleid, $dpo->id, $context->id);
624
625 // Map only the manager role to the DPO role.
626 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
627
628 // User is a DPO.
629 $this->assertTrue(api::is_site_dpo($dpo->id));
630 // User is not a DPO.
631 $this->assertFalse(api::is_site_dpo($nondpo->id));
632 }
633
634 /**
635 * Data provider function for test_notify_dpo
636 *
637 * @return array
638 */
639 public function notify_dpo_provider() {
640 return [
ba5b59c0
JP
641 [false, api::DATAREQUEST_TYPE_EXPORT, 'requesttypeexport', 'Export my user data'],
642 [false, api::DATAREQUEST_TYPE_DELETE, 'requesttypedelete', 'Delete my user data'],
643 [false, api::DATAREQUEST_TYPE_OTHERS, 'requesttypeothers', 'Nothing. Just wanna say hi'],
644 [true, api::DATAREQUEST_TYPE_EXPORT, 'requesttypeexport', 'Admin export data of another user'],
5efc1f9e
DM
645 ];
646 }
647
648 /**
649 * Test for api::notify_dpo()
650 *
651 * @dataProvider notify_dpo_provider
ba5b59c0 652 * @param bool $byadmin Whether the admin requests data on behalf of the user
5efc1f9e
DM
653 * @param int $type The request type
654 * @param string $typestringid The request lang string identifier
ba5b59c0 655 * @param string $comments The requestor's message to the DPO.
5efc1f9e 656 */
ba5b59c0 657 public function test_notify_dpo($byadmin, $type, $typestringid, $comments) {
5efc1f9e
DM
658 $generator = new testing_data_generator();
659 $user1 = $generator->create_user();
ba5b59c0
JP
660 // Let's just use admin as DPO (It's the default if not set).
661 $dpo = get_admin();
662 if ($byadmin) {
663 $this->setAdminUser();
664 $requestedby = $dpo;
665 } else {
666 $this->setUser($user1);
667 $requestedby = $user1;
668 }
5efc1f9e 669
ba5b59c0
JP
670 // Make a data request for user 1.
671 $request = api::create_data_request($user1->id, $type, $comments);
5efc1f9e
DM
672
673 $sink = $this->redirectMessages();
5efc1f9e
DM
674 $messageid = api::notify_dpo($dpo, $request);
675 $this->assertNotFalse($messageid);
676 $messages = $sink->get_messages();
677 $this->assertCount(1, $messages);
678 $message = reset($messages);
679
680 // Check some of the message properties.
ba5b59c0 681 $this->assertEquals($requestedby->id, $message->useridfrom);
5efc1f9e
DM
682 $this->assertEquals($dpo->id, $message->useridto);
683 $typestring = get_string($typestringid, 'tool_dataprivacy');
684 $subject = get_string('datarequestemailsubject', 'tool_dataprivacy', $typestring);
685 $this->assertEquals($subject, $message->subject);
686 $this->assertEquals('tool_dataprivacy', $message->component);
687 $this->assertEquals('contactdataprotectionofficer', $message->eventtype);
688 $this->assertContains(fullname($dpo), $message->fullmessage);
689 $this->assertContains(fullname($user1), $message->fullmessage);
690 }
691
692 /**
693 * Test of creating purpose as a user without privileges.
694 */
695 public function test_create_purpose_non_dpo_user() {
696 $pleb = $this->getDataGenerator()->create_user();
697
698 $this->setUser($pleb);
699 $this->expectException(required_capability_exception::class);
700 api::create_purpose((object)[
701 'name' => 'aaa',
702 'description' => '<b>yeah</b>',
703 'descriptionformat' => 1,
704 'retentionperiod' => 'PT1M'
705 ]);
706 }
707
708 /**
709 * Test fetching of purposes as a user without privileges.
710 */
711 public function test_get_purposes_non_dpo_user() {
712 $pleb = $this->getDataGenerator()->create_user();
713 $this->setAdminUser();
714 api::create_purpose((object)[
715 'name' => 'bbb',
716 'description' => '<b>yeah</b>',
717 'descriptionformat' => 1,
0462786a
JP
718 'retentionperiod' => 'PT1M',
719 'lawfulbases' => 'gdpr_art_6_1_a'
5efc1f9e
DM
720 ]);
721
722 $this->setUser($pleb);
723 $this->expectException(required_capability_exception::class);
724 api::get_purposes();
725 }
726
727 /**
728 * Test updating of purpose as a user without privileges.
729 */
730 public function test_update_purposes_non_dpo_user() {
731 $pleb = $this->getDataGenerator()->create_user();
732 $this->setAdminUser();
733 $purpose = api::create_purpose((object)[
734 'name' => 'bbb',
735 'description' => '<b>yeah</b>',
736 'descriptionformat' => 1,
0462786a
JP
737 'retentionperiod' => 'PT1M',
738 'lawfulbases' => 'gdpr_art_6_1_a'
5efc1f9e
DM
739 ]);
740
741 $this->setUser($pleb);
742 $this->expectException(required_capability_exception::class);
743 $purpose->set('retentionperiod', 'PT2M');
744 api::update_purpose($purpose->to_record());
745 }
746
747 /**
748 * Test purpose deletion as a user without privileges.
749 */
750 public function test_delete_purpose_non_dpo_user() {
751 $pleb = $this->getDataGenerator()->create_user();
752 $this->setAdminUser();
753 $purpose = api::create_purpose((object)[
754 'name' => 'bbb',
755 'description' => '<b>yeah</b>',
756 'descriptionformat' => 1,
0462786a
JP
757 'retentionperiod' => 'PT1M',
758 'lawfulbases' => 'gdpr_art_6_1_a'
5efc1f9e
DM
759 ]);
760
761 $this->setUser($pleb);
762 $this->expectException(required_capability_exception::class);
763 api::delete_purpose($purpose->get('id'));
764 }
765
766 /**
767 * Test data purposes CRUD actions.
768 *
769 * @return null
770 */
771 public function test_purpose_crud() {
772
773 $this->setAdminUser();
774
775 // Add.
776 $purpose = api::create_purpose((object)[
777 'name' => 'bbb',
778 'description' => '<b>yeah</b>',
779 'descriptionformat' => 1,
0462786a
JP
780 'retentionperiod' => 'PT1M',
781 'lawfulbases' => 'gdpr_art_6_1_a,gdpr_art_6_1_c,gdpr_art_6_1_e'
5efc1f9e
DM
782 ]);
783 $this->assertInstanceOf('\tool_dataprivacy\purpose', $purpose);
784 $this->assertEquals('bbb', $purpose->get('name'));
785 $this->assertEquals('PT1M', $purpose->get('retentionperiod'));
0462786a 786 $this->assertEquals('gdpr_art_6_1_a,gdpr_art_6_1_c,gdpr_art_6_1_e', $purpose->get('lawfulbases'));
5efc1f9e
DM
787
788 // Update.
789 $purpose->set('retentionperiod', 'PT2M');
790 $purpose = api::update_purpose($purpose->to_record());
791 $this->assertEquals('PT2M', $purpose->get('retentionperiod'));
792
793 // Retrieve.
0462786a 794 $purpose = api::create_purpose((object)['name' => 'aaa', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a']);
5efc1f9e
DM
795 $purposes = api::get_purposes();
796 $this->assertCount(2, $purposes);
797 $this->assertEquals('aaa', $purposes[0]->get('name'));
798 $this->assertEquals('bbb', $purposes[1]->get('name'));
799
800 // Delete.
801 api::delete_purpose($purposes[0]->get('id'));
802 $this->assertCount(1, api::get_purposes());
803 api::delete_purpose($purposes[1]->get('id'));
804 $this->assertCount(0, api::get_purposes());
805 }
806
807 /**
808 * Test creation of data categories as a user without privileges.
809 */
810 public function test_create_category_non_dpo_user() {
811 $pleb = $this->getDataGenerator()->create_user();
812
813 $this->setUser($pleb);
814 $this->expectException(required_capability_exception::class);
815 api::create_category((object)[
816 'name' => 'bbb',
817 'description' => '<b>yeah</b>',
818 'descriptionformat' => 1
819 ]);
820 }
821
822 /**
823 * Test fetching of data categories as a user without privileges.
824 */
825 public function test_get_categories_non_dpo_user() {
826 $pleb = $this->getDataGenerator()->create_user();
827
828 $this->setAdminUser();
829 api::create_category((object)[
830 'name' => 'bbb',
831 'description' => '<b>yeah</b>',
832 'descriptionformat' => 1
833 ]);
834
835 // Back to a regular user.
836 $this->setUser($pleb);
837 $this->expectException(required_capability_exception::class);
838 api::get_categories();
839 }
840
841 /**
842 * Test updating of data category as a user without privileges.
843 */
844 public function test_update_category_non_dpo_user() {
845 $pleb = $this->getDataGenerator()->create_user();
846
847 $this->setAdminUser();
848 $category = api::create_category((object)[
849 'name' => 'bbb',
850 'description' => '<b>yeah</b>',
851 'descriptionformat' => 1
852 ]);
853
854 // Back to a regular user.
855 $this->setUser($pleb);
856 $this->expectException(required_capability_exception::class);
857 $category->set('name', 'yeah');
858 api::update_category($category->to_record());
859 }
860
861 /**
862 * Test deletion of data category as a user without privileges.
863 */
864 public function test_delete_category_non_dpo_user() {
865 $pleb = $this->getDataGenerator()->create_user();
866
867 $this->setAdminUser();
868 $category = api::create_category((object)[
869 'name' => 'bbb',
870 'description' => '<b>yeah</b>',
871 'descriptionformat' => 1
872 ]);
873
874 // Back to a regular user.
875 $this->setUser($pleb);
876 $this->expectException(required_capability_exception::class);
877 api::delete_category($category->get('id'));
878 $this->fail('Users shouldn\'t be allowed to manage categories by default');
879 }
880
881 /**
882 * Test data categories CRUD actions.
883 *
884 * @return null
885 */
886 public function test_category_crud() {
887
888 $this->setAdminUser();
889
890 // Add.
891 $category = api::create_category((object)[
892 'name' => 'bbb',
893 'description' => '<b>yeah</b>',
894 'descriptionformat' => 1
895 ]);
896 $this->assertInstanceOf('\tool_dataprivacy\category', $category);
897 $this->assertEquals('bbb', $category->get('name'));
898
899 // Update.
900 $category->set('name', 'bcd');
901 $category = api::update_category($category->to_record());
902 $this->assertEquals('bcd', $category->get('name'));
903
904 // Retrieve.
905 $category = api::create_category((object)['name' => 'aaa']);
906 $categories = api::get_categories();
907 $this->assertCount(2, $categories);
908 $this->assertEquals('aaa', $categories[0]->get('name'));
909 $this->assertEquals('bcd', $categories[1]->get('name'));
910
911 // Delete.
912 api::delete_category($categories[0]->get('id'));
913 $this->assertCount(1, api::get_categories());
914 api::delete_category($categories[1]->get('id'));
915 $this->assertCount(0, api::get_categories());
916 }
917
918 /**
919 * Test context instances.
920 *
921 * @return null
922 */
923 public function test_context_instances() {
924 global $DB;
925
926 $this->setAdminUser();
927
928 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
929
930 $coursecontext1 = \context_course::instance($courses[0]->id);
931 $coursecontext2 = \context_course::instance($courses[1]->id);
932
a8a69050
DM
933 $record1 = (object)['contextid' => $coursecontext1->id, 'purposeid' => $purposes[0]->get('id'),
934 'categoryid' => $categories[0]->get('id')];
5efc1f9e
DM
935 $contextinstance1 = api::set_context_instance($record1);
936
a8a69050
DM
937 $record2 = (object)['contextid' => $coursecontext2->id, 'purposeid' => $purposes[1]->get('id'),
938 'categoryid' => $categories[1]->get('id')];
5efc1f9e
DM
939 $contextinstance2 = api::set_context_instance($record2);
940
941 $this->assertCount(2, $DB->get_records('tool_dataprivacy_ctxinstance'));
942
943 api::unset_context_instance($contextinstance1);
944 $this->assertCount(1, $DB->get_records('tool_dataprivacy_ctxinstance'));
945
946 $update = (object)['id' => $contextinstance2->get('id'), 'contextid' => $coursecontext2->id,
947 'purposeid' => $purposes[0]->get('id'), 'categoryid' => $categories[0]->get('id')];
948 $contextinstance2 = api::set_context_instance($update);
949 $this->assertCount(1, $DB->get_records('tool_dataprivacy_ctxinstance'));
950 }
951
952 /**
953 * Test contextlevel.
954 *
955 * @return null
956 */
957 public function test_contextlevel() {
958 global $DB;
959
960 $this->setAdminUser();
961 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
962
963 $record = (object)[
964 'purposeid' => $purposes[0]->get('id'),
965 'categoryid' => $categories[0]->get('id'),
966 'contextlevel' => CONTEXT_SYSTEM,
967 ];
968 $contextlevel = api::set_contextlevel($record);
969 $this->assertInstanceOf('\tool_dataprivacy\contextlevel', $contextlevel);
970 $this->assertEquals($record->contextlevel, $contextlevel->get('contextlevel'));
971 $this->assertEquals($record->purposeid, $contextlevel->get('purposeid'));
972 $this->assertEquals($record->categoryid, $contextlevel->get('categoryid'));
973
974 // Now update it.
975 $record->purposeid = $purposes[1]->get('id');
976 $contextlevel = api::set_contextlevel($record);
977 $this->assertEquals($record->contextlevel, $contextlevel->get('contextlevel'));
978 $this->assertEquals($record->purposeid, $contextlevel->get('purposeid'));
979 $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxlevel'));
980
981 $record->contextlevel = CONTEXT_USER;
982 $contextlevel = api::set_contextlevel($record);
983 $this->assertEquals(2, $DB->count_records('tool_dataprivacy_ctxlevel'));
984 }
985
986 /**
987 * Test effective context levels purpose and category defaults.
988 *
989 * @return null
990 */
991 public function test_effective_contextlevel_defaults() {
992 $this->setAdminUser();
993
994 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
995
996 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_SYSTEM);
997 $this->assertEquals(false, $purposeid);
998 $this->assertEquals(false, $categoryid);
999
1000 list($purposevar, $categoryvar) = data_registry::var_names_from_context(
1001 \context_helper::get_class_for_level(CONTEXT_SYSTEM)
1002 );
1003 set_config($purposevar, $purposes[0]->get('id'), 'tool_dataprivacy');
1004
1005 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_SYSTEM);
1006 $this->assertEquals($purposes[0]->get('id'), $purposeid);
1007 $this->assertEquals(false, $categoryid);
1008
1009 // Course inherits from system if not defined.
1010 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_COURSE);
1011 $this->assertEquals($purposes[0]->get('id'), $purposeid);
1012 $this->assertEquals(false, $categoryid);
1013
1014 // Course defined values should have preference.
1015 list($purposevar, $categoryvar) = data_registry::var_names_from_context(
1016 \context_helper::get_class_for_level(CONTEXT_COURSE)
1017 );
1018 set_config($purposevar, $purposes[1]->get('id'), 'tool_dataprivacy');
1019 set_config($categoryvar, $categories[0]->get('id'), 'tool_dataprivacy');
1020
1021 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_COURSE);
1022 $this->assertEquals($purposes[1]->get('id'), $purposeid);
1023 $this->assertEquals($categories[0]->get('id'), $categoryid);
1024
1025 // Context level defaults are also allowed to be set to 'inherit'.
1026 set_config($purposevar, context_instance::INHERIT, 'tool_dataprivacy');
1027
1028 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_COURSE);
1029 $this->assertEquals($purposes[0]->get('id'), $purposeid);
1030 $this->assertEquals($categories[0]->get('id'), $categoryid);
1031
1032 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_MODULE);
1033 $this->assertEquals($purposes[0]->get('id'), $purposeid);
1034 $this->assertEquals($categories[0]->get('id'), $categoryid);
1035 }
1036
1037 /**
1038 * Test effective contextlevel return.
1039 *
1040 * @return null
1041 */
1042 public function test_effective_contextlevel() {
1043 $this->setAdminUser();
1044
1045 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
1046
1047 // Set the system context level to purpose 1.
1048 $record = (object)[
1049 'contextlevel' => CONTEXT_SYSTEM,
1050 'purposeid' => $purposes[1]->get('id'),
1051 'categoryid' => $categories[1]->get('id'),
1052 ];
1053 api::set_contextlevel($record);
1054
1055 $purpose = api::get_effective_contextlevel_purpose(CONTEXT_SYSTEM);
1056 $this->assertEquals($purposes[1]->get('id'), $purpose->get('id'));
1057
a8a69050 1058 // Value 'not set' will get the default value for the context level. For context level defaults
5efc1f9e
DM
1059 // both 'not set' and 'inherit' result in inherit, so the parent context (system) default
1060 // will be retrieved.
1061 $purpose = api::get_effective_contextlevel_purpose(CONTEXT_USER);
1062 $this->assertEquals($purposes[1]->get('id'), $purpose->get('id'));
1063
1064 // The behaviour forcing an inherit from context system should result in the same effective
1065 // purpose.
1066 $record->purposeid = context_instance::INHERIT;
1067 $record->contextlevel = CONTEXT_USER;
1068 api::set_contextlevel($record);
1069 $purpose = api::get_effective_contextlevel_purpose(CONTEXT_USER);
1070 $this->assertEquals($purposes[1]->get('id'), $purpose->get('id'));
1071
1072 $record->purposeid = $purposes[2]->get('id');
1073 $record->contextlevel = CONTEXT_USER;
1074 api::set_contextlevel($record);
1075
1076 $purpose = api::get_effective_contextlevel_purpose(CONTEXT_USER);
1077 $this->assertEquals($purposes[2]->get('id'), $purpose->get('id'));
1078
1079 // Only system and user allowed.
1080 $this->expectException(coding_exception::class);
1081 $record->contextlevel = CONTEXT_COURSE;
1082 $record->purposeid = $purposes[1]->get('id');
1083 api::set_contextlevel($record);
1084 }
1085
1086 /**
1087 * Test effective context purposes and categories.
1088 *
1089 * @return null
1090 */
1091 public function test_effective_context() {
1092 $this->setAdminUser();
1093
1094 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
1095
1096 // Define system defaults (all context levels below will inherit).
1097 list($purposevar, $categoryvar) = data_registry::var_names_from_context(
1098 \context_helper::get_class_for_level(CONTEXT_SYSTEM)
1099 );
1100 set_config($purposevar, $purposes[0]->get('id'), 'tool_dataprivacy');
1101 set_config($categoryvar, $categories[0]->get('id'), 'tool_dataprivacy');
1102
1103 // Define course defaults.
1104 list($purposevar, $categoryvar) = data_registry::var_names_from_context(
1105 \context_helper::get_class_for_level(CONTEXT_COURSE)
1106 );
1107 set_config($purposevar, $purposes[1]->get('id'), 'tool_dataprivacy');
1108 set_config($categoryvar, $categories[1]->get('id'), 'tool_dataprivacy');
1109
1110 $course0context = \context_course::instance($courses[0]->id);
1111 $course1context = \context_course::instance($courses[1]->id);
1112 $mod0context = \context_module::instance($modules[0]->cmid);
1113 $mod1context = \context_module::instance($modules[1]->cmid);
1114
1115 // Set course instance values.
1116 $record = (object)[
1117 'contextid' => $course0context->id,
1118 'purposeid' => $purposes[1]->get('id'),
1119 'categoryid' => $categories[2]->get('id'),
1120 ];
1121 api::set_context_instance($record);
1122 $category = api::get_effective_context_category($course0context);
1123 $this->assertEquals($record->categoryid, $category->get('id'));
1124
1125 // Module instances get the context level default if nothing specified.
1126 $category = api::get_effective_context_category($mod0context);
1127 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
1128
1129 // Module instances get the parent context category if they inherit.
1130 $record->contextid = $mod0context->id;
1131 $record->categoryid = context_instance::INHERIT;
1132 api::set_context_instance($record);
1133 $category = api::get_effective_context_category($mod0context);
1134 $this->assertEquals($categories[2]->get('id'), $category->get('id'));
1135
1136 // The $forcedvalue param allows us to override the actual value (method php-docs for more info).
1137 $category = api::get_effective_context_category($mod0context, $categories[1]->get('id'));
1138 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
1139 $category = api::get_effective_context_category($mod0context, $categories[0]->get('id'));
1140 $this->assertEquals($categories[0]->get('id'), $category->get('id'));
1141
1142 // Module instances get the parent context category if they inherit; in
1143 // this case the parent context category is not set so it should use the
1144 // context level default (see 'Define course defaults' above).
1145 $record->contextid = $mod1context->id;
1146 $record->categoryid = context_instance::INHERIT;
1147 api::set_context_instance($record);
1148 $category = api::get_effective_context_category($mod1context);
1149 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
1150
1151 // User instances use the value set at user context level instead of the user default.
1152
1153 // User defaults to cat 0 and user context level to 1.
1154 list($purposevar, $categoryvar) = data_registry::var_names_from_context(
1155 \context_helper::get_class_for_level(CONTEXT_USER)
1156 );
1157 set_config($purposevar, $purposes[0]->get('id'), 'tool_dataprivacy');
1158 set_config($categoryvar, $categories[0]->get('id'), 'tool_dataprivacy');
1159 $usercontextlevel = (object)[
1160 'contextlevel' => CONTEXT_USER,
1161 'purposeid' => $purposes[1]->get('id'),
1162 'categoryid' => $categories[1]->get('id'),
1163 ];
1164 api::set_contextlevel($usercontextlevel);
1165
1166 $newuser = $this->getDataGenerator()->create_user();
1167 $usercontext = \context_user::instance($newuser->id);
1168 $category = api::get_effective_context_category($usercontext);
1169 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
1170 }
1171
1172 /**
1173 * Tests the deletion of expired contexts.
1174 *
1175 * @return null
1176 */
1177 public function test_expired_context_deletion() {
1178 global $DB;
1179
1180 $this->setAdminUser();
1181
1182 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
1183
1184 $course0context = \context_course::instance($courses[0]->id);
1185 $course1context = \context_course::instance($courses[1]->id);
1186
1187 $expiredcontext0 = api::create_expired_context($course0context->id);
1188 $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired'));
1189 $expiredcontext1 = api::create_expired_context($course1context->id);
1190 $this->assertEquals(2, $DB->count_records('tool_dataprivacy_ctxexpired'));
1191
1192 api::delete_expired_context($expiredcontext0->get('id'));
1193 $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired'));
1194 }
1195
1196 /**
1197 * Tests the status of expired contexts.
1198 *
1199 * @return null
1200 */
1201 public function test_expired_context_status() {
1202 global $DB;
1203
1204 $this->setAdminUser();
1205
1206 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
1207
1208 $course0context = \context_course::instance($courses[0]->id);
1209
1210 $expiredcontext = api::create_expired_context($course0context->id);
1211
1212 // Default status.
1213 $this->assertEquals(expired_context::STATUS_EXPIRED, $expiredcontext->get('status'));
1214
1215 api::set_expired_context_status($expiredcontext, expired_context::STATUS_APPROVED);
1216 $this->assertEquals(expired_context::STATUS_APPROVED, $expiredcontext->get('status'));
1217 }
1218
1219 /**
1220 * Creates test purposes and categories.
1221 *
1222 * @return null
1223 */
1224 protected function add_purposes_and_categories() {
1225
0462786a
JP
1226 $purpose1 = api::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'PT1H', 'lawfulbases' => 'gdpr_art_6_1_a']);
1227 $purpose2 = api::create_purpose((object)['name' => 'p2', 'retentionperiod' => 'PT2H', 'lawfulbases' => 'gdpr_art_6_1_b']);
1228 $purpose3 = api::create_purpose((object)['name' => 'p3', 'retentionperiod' => 'PT3H', 'lawfulbases' => 'gdpr_art_6_1_c']);
5efc1f9e
DM
1229
1230 $cat1 = api::create_category((object)['name' => 'a']);
1231 $cat2 = api::create_category((object)['name' => 'b']);
1232 $cat3 = api::create_category((object)['name' => 'c']);
1233
1234 $course1 = $this->getDataGenerator()->create_course();
1235 $course2 = $this->getDataGenerator()->create_course();
1236
1237 $module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1));
1238 $module2 = $this->getDataGenerator()->create_module('resource', array('course' => $course2));
1239
1240 return [
1241 [$purpose1, $purpose2, $purpose3],
1242 [$cat1, $cat2, $cat3],
1243 [$course1, $course2],
1244 [$module1, $module2]
1245 ];
1246 }
00293f90
AN
1247
1248 /**
1249 * Test that delete requests filter out protected purpose contexts.
1250 */
1251 public function test_add_request_contexts_with_status_delete() {
1252 $data = $this->setup_test_add_request_contexts_with_status(api::DATAREQUEST_TYPE_DELETE);
1253 $contextids = $data->list->get_contextids();
1254
1255 $this->assertCount(1, $contextids);
1256 $this->assertEquals($data->contexts->unprotected, $contextids);
1257 }
1258
1259 /**
1260 * Test that export requests don't filter out protected purpose contexts.
1261 */
1262 public function test_add_request_contexts_with_status_export() {
1263 $data = $this->setup_test_add_request_contexts_with_status(api::DATAREQUEST_TYPE_EXPORT);
1264 $contextids = $data->list->get_contextids();
1265
1266 $this->assertCount(2, $contextids);
1267 $this->assertEquals($data->contexts->used, $contextids, '', 0.0, 10, true);
1268 }
1269
1270 /**
1271 * Perform setup for the test_add_request_contexts_with_status_xxxxx tests.
1272 *
1273 * @param int $type The type of request to create
1274 * @return \stdClass
1275 */
1276 protected function setup_test_add_request_contexts_with_status($type) {
1277 $this->setAdminUser();
1278
1279 // User under test.
1280 $s1 = $this->getDataGenerator()->create_user();
1281
1282 // Create three sample contexts.
1283 // 1 which should not be returned; and
1284 // 1 which will be returned and is not protected; and
1285 // 1 which will be returned and is protected.
1286
1287 $c1 = $this->getDataGenerator()->create_course();
1288 $c2 = $this->getDataGenerator()->create_course();
1289 $c3 = $this->getDataGenerator()->create_course();
1290
1291 $ctx1 = \context_course::instance($c1->id);
1292 $ctx2 = \context_course::instance($c2->id);
1293 $ctx3 = \context_course::instance($c3->id);
1294
1295 $unprotected = api::create_purpose((object)[
1296 'name' => 'Unprotected', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a']);
1297 $protected = api::create_purpose((object) [
1298 'name' => 'Protected', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a', 'protected' => true]);
1299
1300 $cat1 = api::create_category((object)['name' => 'a']);
1301
1302 // Set the defaults.
1303 list($purposevar, $categoryvar) = data_registry::var_names_from_context(
1304 \context_helper::get_class_for_level(CONTEXT_SYSTEM)
1305 );
1306 set_config($purposevar, $unprotected->get('id'), 'tool_dataprivacy');
1307 set_config($categoryvar, $cat1->get('id'), 'tool_dataprivacy');
1308
1309 $contextinstance1 = api::set_context_instance((object) [
1310 'contextid' => $ctx1->id,
1311 'purposeid' => $unprotected->get('id'),
1312 'categoryid' => $cat1->get('id'),
1313 ]);
1314
1315 $contextinstance2 = api::set_context_instance((object) [
1316 'contextid' => $ctx2->id,
1317 'purposeid' => $unprotected->get('id'),
1318 'categoryid' => $cat1->get('id'),
1319 ]);
1320
1321 $contextinstance3 = api::set_context_instance((object) [
1322 'contextid' => $ctx3->id,
1323 'purposeid' => $protected->get('id'),
1324 'categoryid' => $cat1->get('id'),
1325 ]);
1326
1327 $collection = new \core_privacy\local\request\contextlist_collection($s1->id);
1328 $contextlist = new \core_privacy\local\request\contextlist();
1329 $contextlist->set_component('tool_dataprivacy');
1330 $contextlist->add_from_sql('SELECT id FROM {context} WHERE id IN(:ctx2, :ctx3)', [
1331 'ctx2' => $ctx2->id,
1332 'ctx3' => $ctx3->id,
1333 ]);
1334
1335 $collection->add_contextlist($contextlist);
1336
1337 // Create the sample data request.
1338 $datarequest = api::create_data_request($s1->id, $type);
1339 $requestid = $datarequest->get('id');
1340
1341 // Add the full collection with contexts 2, and 3.
1342 api::add_request_contexts_with_status($collection, $requestid, \tool_dataprivacy\contextlist_context::STATUS_PENDING);
1343
1344 // Mark it as approved.
1345 api::update_request_contexts_with_status($requestid, \tool_dataprivacy\contextlist_context::STATUS_APPROVED);
1346
1347 // Fetch the list.
1348 $approvedcollection = api::get_approved_contextlist_collection_for_request($datarequest);
1349
1350 return (object) [
1351 'contexts' => (object) [
1352 'unused' => [
1353 $ctx1->id,
1354 ],
1355 'used' => [
1356 $ctx2->id,
1357 $ctx3->id,
1358 ],
1359 'unprotected' => [
1360 $ctx2->id,
1361 ],
1362 'protected' => [
1363 $ctx3->id,
1364 ],
1365 ],
1366 'list' => $approvedcollection->get_contextlist_for_component('tool_dataprivacy'),
1367 ];
1368 }
5efc1f9e 1369}