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/>.
20 * @package tool_dataprivacy
21 * @copyright 2018 Jun Pataleta
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 use core\invalid_persistent_exception
;
26 use core\task\manager
;
27 use tool_dataprivacy\context_instance
;
28 use tool_dataprivacy\api
;
29 use tool_dataprivacy\data_registry
;
30 use tool_dataprivacy\expired_context
;
31 use tool_dataprivacy\data_request
;
32 use tool_dataprivacy\task\initiate_data_request_task
;
33 use tool_dataprivacy\task\process_data_request_task
;
35 defined('MOODLE_INTERNAL') ||
die();
41 * @package tool_dataprivacy
42 * @copyright 2018 Jun Pataleta
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 class tool_dataprivacy_api_testcase
extends advanced_testcase
{
50 public function setUp() {
51 $this->resetAfterTest();
55 * Test for api::update_request_status().
57 public function test_update_request_status() {
58 $generator = new testing_data_generator();
59 $s1 = $generator->create_user();
61 // Create the sample data request.
62 $datarequest = api
::create_data_request($s1->id
, api
::DATAREQUEST_TYPE_EXPORT
);
64 $requestid = $datarequest->get('id');
66 // Update with a valid status.
67 $result = api
::update_request_status($requestid, api
::DATAREQUEST_STATUS_COMPLETE
);
68 $this->assertTrue($result);
70 // Fetch the request record again.
71 $datarequest = new data_request($requestid);
72 $this->assertEquals(api
::DATAREQUEST_STATUS_COMPLETE
, $datarequest->get('status'));
74 // Update with an invalid status.
75 $this->expectException(invalid_persistent_exception
::class);
76 api
::update_request_status($requestid, -1);
80 * Test for api::get_site_dpos() when there are no users with the DPO role.
82 public function test_get_site_dpos_no_dpos() {
85 $dpos = api
::get_site_dpos();
86 $this->assertCount(1, $dpos);
88 $this->assertEquals($admin->id
, $dpo->id
);
92 * Test for api::get_site_dpos() when there are no users with the DPO role.
94 public function test_get_site_dpos() {
96 $generator = new testing_data_generator();
97 $u1 = $generator->create_user();
98 $u2 = $generator->create_user();
100 $context = context_system
::instance();
102 // Give the manager role with the capability to manage data requests.
103 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
104 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW
, $managerroleid, $context->id
, true);
105 // Assign u1 as a manager.
106 role_assign($managerroleid, $u1->id
, $context->id
);
108 // Give the editing teacher role with the capability to manage data requests.
109 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher'));
110 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW
, $editingteacherroleid, $context->id
, true);
111 // Assign u1 as an editing teacher as well.
112 role_assign($editingteacherroleid, $u1->id
, $context->id
);
113 // Assign u2 as an editing teacher.
114 role_assign($editingteacherroleid, $u2->id
, $context->id
);
116 // Only map the manager role to the DPO role.
117 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
119 $dpos = api
::get_site_dpos();
120 $this->assertCount(1, $dpos);
122 $this->assertEquals($u1->id
, $dpo->id
);
126 * Test for api::approve_data_request().
128 public function test_approve_data_request() {
131 $generator = new testing_data_generator();
132 $s1 = $generator->create_user();
133 $u1 = $generator->create_user();
135 $context = context_system
::instance();
138 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
139 // Give the manager role with the capability to manage data requests.
140 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW
, $managerroleid, $context->id
, true);
141 // Assign u1 as a manager.
142 role_assign($managerroleid, $u1->id
, $context->id
);
144 // Map the manager role to the DPO role.
145 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
147 // Create the sample data request.
148 $datarequest = api
::create_data_request($s1->id
, api
::DATAREQUEST_TYPE_EXPORT
);
149 $requestid = $datarequest->get('id');
151 // Make this ready for approval.
152 api
::update_request_status($requestid, api
::DATAREQUEST_STATUS_AWAITING_APPROVAL
);
155 $result = api
::approve_data_request($requestid);
156 $this->assertTrue($result);
157 $datarequest = new data_request($requestid);
158 $this->assertEquals($u1->id
, $datarequest->get('dpo'));
159 $this->assertEquals(api
::DATAREQUEST_STATUS_APPROVED
, $datarequest->get('status'));
161 // Test adhoc task creation.
162 $adhoctasks = manager
::get_adhoc_tasks(process_data_request_task
::class);
163 $this->assertCount(1, $adhoctasks);
167 * Test for api::approve_data_request() with the request not yet waiting for approval.
169 public function test_approve_data_request_not_yet_ready() {
172 $generator = new testing_data_generator();
173 $s1 = $generator->create_user();
174 $u1 = $generator->create_user();
176 $context = context_system
::instance();
179 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
180 // Give the manager role with the capability to manage data requests.
181 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW
, $managerroleid, $context->id
, true);
182 // Assign u1 as a manager.
183 role_assign($managerroleid, $u1->id
, $context->id
);
185 // Map the manager role to the DPO role.
186 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
188 // Create the sample data request.
189 $datarequest = api
::create_data_request($s1->id
, api
::DATAREQUEST_TYPE_EXPORT
);
190 $requestid = $datarequest->get('id');
193 $this->expectException(moodle_exception
::class);
194 api
::approve_data_request($requestid);
198 * Test for api::approve_data_request() when called by a user who doesn't have the DPO role.
200 public function test_approve_data_request_non_dpo_user() {
201 $generator = new testing_data_generator();
202 $student = $generator->create_user();
203 $teacher = $generator->create_user();
205 // Create the sample data request.
206 $datarequest = api
::create_data_request($student->id
, api
::DATAREQUEST_TYPE_EXPORT
);
208 $requestid = $datarequest->get('id');
210 // Login as a user without DPO role.
211 $this->setUser($teacher);
212 $this->expectException(required_capability_exception
::class);
213 api
::approve_data_request($requestid);
217 * Test for api::can_contact_dpo()
219 public function test_can_contact_dpo() {
220 // Default ('contactdataprotectionofficer' is enabled by default).
221 $this->assertTrue(api
::can_contact_dpo());
224 set_config('contactdataprotectionofficer', 0, 'tool_dataprivacy');
225 $this->assertFalse(api
::can_contact_dpo());
228 set_config('contactdataprotectionofficer', 1, 'tool_dataprivacy');
229 $this->assertTrue(api
::can_contact_dpo());
233 * Test for api::can_manage_data_requests()
235 public function test_can_manage_data_requests() {
238 // No configured site DPOs yet.
239 $admin = get_admin();
240 $this->assertTrue(api
::can_manage_data_requests($admin->id
));
242 $generator = new testing_data_generator();
243 $dpo = $generator->create_user();
244 $nondpocapable = $generator->create_user();
245 $nondpoincapable = $generator->create_user();
247 $context = context_system
::instance();
250 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
251 // Give the manager role with the capability to manage data requests.
252 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW
, $managerroleid, $context->id
, true);
253 // Assign u1 as a manager.
254 role_assign($managerroleid, $dpo->id
, $context->id
);
256 // Editing teacher role.
257 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher'));
258 // Give the editing teacher role with the capability to manage data requests.
259 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW
, $managerroleid, $context->id
, true);
260 // Assign u2 as an editing teacher.
261 role_assign($editingteacherroleid, $nondpocapable->id
, $context->id
);
263 // Map only the manager role to the DPO role.
264 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
266 // User with capability and has DPO role.
267 $this->assertTrue(api
::can_manage_data_requests($dpo->id
));
268 // User with capability but has no DPO role.
269 $this->assertFalse(api
::can_manage_data_requests($nondpocapable->id
));
270 // User without the capability and has no DPO role.
271 $this->assertFalse(api
::can_manage_data_requests($nondpoincapable->id
));
275 * Test for api::create_data_request()
277 public function test_create_data_request() {
278 $generator = new testing_data_generator();
279 $user = $generator->create_user();
280 $comment = 'sample comment';
283 $this->setUser($user->id
);
285 // Test data request creation.
286 $datarequest = api
::create_data_request($user->id
, api
::DATAREQUEST_TYPE_EXPORT
, $comment);
287 $this->assertEquals($user->id
, $datarequest->get('userid'));
288 $this->assertEquals($user->id
, $datarequest->get('requestedby'));
289 $this->assertEquals(api
::DATAREQUEST_TYPE_EXPORT
, $datarequest->get('type'));
290 $this->assertEquals(api
::DATAREQUEST_STATUS_PENDING
, $datarequest->get('status'));
291 $this->assertEquals($comment, $datarequest->get('comments'));
293 // Test adhoc task creation.
294 $adhoctasks = manager
::get_adhoc_tasks(initiate_data_request_task
::class);
295 $this->assertCount(1, $adhoctasks);
299 * Test for api::deny_data_request()
301 public function test_deny_data_request() {
302 $generator = new testing_data_generator();
303 $user = $generator->create_user();
304 $comment = 'sample comment';
307 $this->setUser($user->id
);
309 // Test data request creation.
310 $datarequest = api
::create_data_request($user->id
, api
::DATAREQUEST_TYPE_EXPORT
, $comment);
312 // Login as the admin (default DPO when no one is set).
313 $this->setAdminUser();
315 // Make this ready for approval.
316 api
::update_request_status($datarequest->get('id'), api
::DATAREQUEST_STATUS_AWAITING_APPROVAL
);
318 // Deny the data request.
319 $result = api
::deny_data_request($datarequest->get('id'));
320 $this->assertTrue($result);
324 * Test for api::deny_data_request()
326 public function test_deny_data_request_without_permissions() {
327 $generator = new testing_data_generator();
328 $user = $generator->create_user();
329 $comment = 'sample comment';
332 $this->setUser($user->id
);
334 // Test data request creation.
335 $datarequest = api
::create_data_request($user->id
, api
::DATAREQUEST_TYPE_EXPORT
, $comment);
337 // Login as a non-DPO user and try to call deny_data_request.
338 $user2 = $generator->create_user();
339 $this->setUser($user2);
340 $this->expectException(required_capability_exception
::class);
341 api
::deny_data_request($datarequest->get('id'));
345 * Test for api::get_data_requests()
347 public function test_get_data_requests() {
348 $generator = new testing_data_generator();
349 $user1 = $generator->create_user();
350 $user2 = $generator->create_user();
351 $comment = 'sample comment';
353 // Make a data request as user 1.
354 $d1 = api
::create_data_request($user1->id
, api
::DATAREQUEST_TYPE_EXPORT
, $comment);
355 // Make a data request as user 2.
356 $d2 = api
::create_data_request($user2->id
, api
::DATAREQUEST_TYPE_EXPORT
, $comment);
358 // Fetching data requests of specific users.
359 $requests = api
::get_data_requests($user1->id
);
360 $this->assertCount(1, $requests);
361 $datarequest = reset($requests);
362 $this->assertEquals($d1->to_record(), $datarequest->to_record());
364 $requests = api
::get_data_requests($user2->id
);
365 $this->assertCount(1, $requests);
366 $datarequest = reset($requests);
367 $this->assertEquals($d2->to_record(), $datarequest->to_record());
369 // Fetching data requests of all users.
371 $this->setGuestUser();
372 $requests = api
::get_data_requests();
373 $this->assertEmpty($requests);
375 // As DPO (admin in this case, which is default if no site DPOs are set).
376 $this->setAdminUser();
377 $requests = api
::get_data_requests();
378 $this->assertCount(2, $requests);
382 * Data provider for test_has_ongoing_request.
384 public function status_provider() {
386 [api
::DATAREQUEST_STATUS_PENDING
, true],
387 [api
::DATAREQUEST_STATUS_PREPROCESSING
, true],
388 [api
::DATAREQUEST_STATUS_AWAITING_APPROVAL
, true],
389 [api
::DATAREQUEST_STATUS_APPROVED
, true],
390 [api
::DATAREQUEST_STATUS_PROCESSING
, true],
391 [api
::DATAREQUEST_STATUS_COMPLETE
, false],
392 [api
::DATAREQUEST_STATUS_CANCELLED
, false],
393 [api
::DATAREQUEST_STATUS_REJECTED
, false],
398 * Test for api::has_ongoing_request()
400 * @dataProvider status_provider
401 * @param int $status The request status.
402 * @param bool $expected The expected result.
404 public function test_has_ongoing_request($status, $expected) {
405 $generator = new testing_data_generator();
406 $user1 = $generator->create_user();
408 // Make a data request as user 1.
409 $request = api
::create_data_request($user1->id
, api
::DATAREQUEST_TYPE_EXPORT
);
411 api
::update_request_status($request->get('id'), $status);
413 // Check if this request is ongoing.
414 $result = api
::has_ongoing_request($user1->id
, api
::DATAREQUEST_TYPE_EXPORT
);
415 $this->assertEquals($expected, $result);
419 * Test for api::is_active()
421 * @dataProvider status_provider
422 * @param int $status The request status
423 * @param bool $expected The expected result
425 public function test_is_active($status, $expected) {
426 // Check if this request is ongoing.
427 $result = api
::is_active($status);
428 $this->assertEquals($expected, $result);
432 * Test for api::is_site_dpo()
434 public function test_is_site_dpo() {
437 // No configured site DPOs yet.
438 $admin = get_admin();
439 $this->assertTrue(api
::is_site_dpo($admin->id
));
441 $generator = new testing_data_generator();
442 $dpo = $generator->create_user();
443 $nondpo = $generator->create_user();
445 $context = context_system
::instance();
448 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
449 // Give the manager role with the capability to manage data requests.
450 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW
, $managerroleid, $context->id
, true);
451 // Assign u1 as a manager.
452 role_assign($managerroleid, $dpo->id
, $context->id
);
454 // Map only the manager role to the DPO role.
455 set_config('dporoles', $managerroleid, 'tool_dataprivacy');
458 $this->assertTrue(api
::is_site_dpo($dpo->id
));
459 // User is not a DPO.
460 $this->assertFalse(api
::is_site_dpo($nondpo->id
));
464 * Data provider function for test_notify_dpo
468 public function notify_dpo_provider() {
470 [api
::DATAREQUEST_TYPE_EXPORT
, 'requesttypeexport'],
471 [api
::DATAREQUEST_TYPE_DELETE
, 'requesttypedelete'],
472 [api
::DATAREQUEST_TYPE_OTHERS
, 'requesttypeothers'],
477 * Test for api::notify_dpo()
479 * @dataProvider notify_dpo_provider
480 * @param int $type The request type
481 * @param string $typestringid The request lang string identifier
483 public function test_notify_dpo($type, $typestringid) {
484 $generator = new testing_data_generator();
485 $user1 = $generator->create_user();
487 // Make a data request as user 1.
488 $this->setUser($user1);
489 $request = api
::create_data_request($user1->id
, $type);
491 $sink = $this->redirectMessages();
492 // Let's just use admin as DPO (It's the default if not set).
494 $messageid = api
::notify_dpo($dpo, $request);
495 $this->assertNotFalse($messageid);
496 $messages = $sink->get_messages();
497 $this->assertCount(1, $messages);
498 $message = reset($messages);
500 // Check some of the message properties.
501 $this->assertEquals($user1->id
, $message->useridfrom
);
502 $this->assertEquals($dpo->id
, $message->useridto
);
503 $typestring = get_string($typestringid, 'tool_dataprivacy');
504 $subject = get_string('datarequestemailsubject', 'tool_dataprivacy', $typestring);
505 $this->assertEquals($subject, $message->subject
);
506 $this->assertEquals('tool_dataprivacy', $message->component
);
507 $this->assertEquals('contactdataprotectionofficer', $message->eventtype
);
508 $this->assertContains(fullname($dpo), $message->fullmessage
);
509 $this->assertContains(fullname($user1), $message->fullmessage
);
513 * Test of creating purpose as a user without privileges.
515 public function test_create_purpose_non_dpo_user() {
516 $pleb = $this->getDataGenerator()->create_user();
518 $this->setUser($pleb);
519 $this->expectException(required_capability_exception
::class);
520 api
::create_purpose((object)[
522 'description' => '<b>yeah</b>',
523 'descriptionformat' => 1,
524 'retentionperiod' => 'PT1M'
529 * Test fetching of purposes as a user without privileges.
531 public function test_get_purposes_non_dpo_user() {
532 $pleb = $this->getDataGenerator()->create_user();
533 $this->setAdminUser();
534 api
::create_purpose((object)[
536 'description' => '<b>yeah</b>',
537 'descriptionformat' => 1,
538 'retentionperiod' => 'PT1M'
541 $this->setUser($pleb);
542 $this->expectException(required_capability_exception
::class);
547 * Test updating of purpose as a user without privileges.
549 public function test_update_purposes_non_dpo_user() {
550 $pleb = $this->getDataGenerator()->create_user();
551 $this->setAdminUser();
552 $purpose = api
::create_purpose((object)[
554 'description' => '<b>yeah</b>',
555 'descriptionformat' => 1,
556 'retentionperiod' => 'PT1M'
559 $this->setUser($pleb);
560 $this->expectException(required_capability_exception
::class);
561 $purpose->set('retentionperiod', 'PT2M');
562 api
::update_purpose($purpose->to_record());
566 * Test purpose deletion as a user without privileges.
568 public function test_delete_purpose_non_dpo_user() {
569 $pleb = $this->getDataGenerator()->create_user();
570 $this->setAdminUser();
571 $purpose = api
::create_purpose((object)[
573 'description' => '<b>yeah</b>',
574 'descriptionformat' => 1,
575 'retentionperiod' => 'PT1M'
578 $this->setUser($pleb);
579 $this->expectException(required_capability_exception
::class);
580 api
::delete_purpose($purpose->get('id'));
584 * Test data purposes CRUD actions.
588 public function test_purpose_crud() {
590 $this->setAdminUser();
593 $purpose = api
::create_purpose((object)[
595 'description' => '<b>yeah</b>',
596 'descriptionformat' => 1,
597 'retentionperiod' => 'PT1M'
599 $this->assertInstanceOf('\tool_dataprivacy\purpose', $purpose);
600 $this->assertEquals('bbb', $purpose->get('name'));
601 $this->assertEquals('PT1M', $purpose->get('retentionperiod'));
604 $purpose->set('retentionperiod', 'PT2M');
605 $purpose = api
::update_purpose($purpose->to_record());
606 $this->assertEquals('PT2M', $purpose->get('retentionperiod'));
609 $purpose = api
::create_purpose((object)['name' => 'aaa', 'retentionperiod' => 'PT1M']);
610 $purposes = api
::get_purposes();
611 $this->assertCount(2, $purposes);
612 $this->assertEquals('aaa', $purposes[0]->get('name'));
613 $this->assertEquals('bbb', $purposes[1]->get('name'));
616 api
::delete_purpose($purposes[0]->get('id'));
617 $this->assertCount(1, api
::get_purposes());
618 api
::delete_purpose($purposes[1]->get('id'));
619 $this->assertCount(0, api
::get_purposes());
623 * Test creation of data categories as a user without privileges.
625 public function test_create_category_non_dpo_user() {
626 $pleb = $this->getDataGenerator()->create_user();
628 $this->setUser($pleb);
629 $this->expectException(required_capability_exception
::class);
630 api
::create_category((object)[
632 'description' => '<b>yeah</b>',
633 'descriptionformat' => 1
638 * Test fetching of data categories as a user without privileges.
640 public function test_get_categories_non_dpo_user() {
641 $pleb = $this->getDataGenerator()->create_user();
643 $this->setAdminUser();
644 api
::create_category((object)[
646 'description' => '<b>yeah</b>',
647 'descriptionformat' => 1
650 // Back to a regular user.
651 $this->setUser($pleb);
652 $this->expectException(required_capability_exception
::class);
653 api
::get_categories();
657 * Test updating of data category as a user without privileges.
659 public function test_update_category_non_dpo_user() {
660 $pleb = $this->getDataGenerator()->create_user();
662 $this->setAdminUser();
663 $category = api
::create_category((object)[
665 'description' => '<b>yeah</b>',
666 'descriptionformat' => 1
669 // Back to a regular user.
670 $this->setUser($pleb);
671 $this->expectException(required_capability_exception
::class);
672 $category->set('name', 'yeah');
673 api
::update_category($category->to_record());
677 * Test deletion of data category as a user without privileges.
679 public function test_delete_category_non_dpo_user() {
680 $pleb = $this->getDataGenerator()->create_user();
682 $this->setAdminUser();
683 $category = api
::create_category((object)[
685 'description' => '<b>yeah</b>',
686 'descriptionformat' => 1
689 // Back to a regular user.
690 $this->setUser($pleb);
691 $this->expectException(required_capability_exception
::class);
692 api
::delete_category($category->get('id'));
693 $this->fail('Users shouldn\'t be allowed to manage categories by default');
697 * Test data categories CRUD actions.
701 public function test_category_crud() {
703 $this->setAdminUser();
706 $category = api
::create_category((object)[
708 'description' => '<b>yeah</b>',
709 'descriptionformat' => 1
711 $this->assertInstanceOf('\tool_dataprivacy\category', $category);
712 $this->assertEquals('bbb', $category->get('name'));
715 $category->set('name', 'bcd');
716 $category = api
::update_category($category->to_record());
717 $this->assertEquals('bcd', $category->get('name'));
720 $category = api
::create_category((object)['name' => 'aaa']);
721 $categories = api
::get_categories();
722 $this->assertCount(2, $categories);
723 $this->assertEquals('aaa', $categories[0]->get('name'));
724 $this->assertEquals('bcd', $categories[1]->get('name'));
727 api
::delete_category($categories[0]->get('id'));
728 $this->assertCount(1, api
::get_categories());
729 api
::delete_category($categories[1]->get('id'));
730 $this->assertCount(0, api
::get_categories());
734 * Test context instances.
738 public function test_context_instances() {
741 $this->setAdminUser();
743 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
745 $coursecontext1 = \context_course
::instance($courses[0]->id
);
746 $coursecontext2 = \context_course
::instance($courses[1]->id
);
748 $record1 = (object)['contextid' => $coursecontext1->id
, 'purposeid' => $purposes[0]->get('id'),
749 'categoryid' => $categories[0]->get('id')];
750 $contextinstance1 = api
::set_context_instance($record1);
752 $record2 = (object)['contextid' => $coursecontext2->id
, 'purposeid' => $purposes[1]->get('id'),
753 'categoryid' => $categories[1]->get('id')];
754 $contextinstance2 = api
::set_context_instance($record2);
756 $this->assertCount(2, $DB->get_records('tool_dataprivacy_ctxinstance'));
758 api
::unset_context_instance($contextinstance1);
759 $this->assertCount(1, $DB->get_records('tool_dataprivacy_ctxinstance'));
761 $update = (object)['id' => $contextinstance2->get('id'), 'contextid' => $coursecontext2->id
,
762 'purposeid' => $purposes[0]->get('id'), 'categoryid' => $categories[0]->get('id')];
763 $contextinstance2 = api
::set_context_instance($update);
764 $this->assertCount(1, $DB->get_records('tool_dataprivacy_ctxinstance'));
772 public function test_contextlevel() {
775 $this->setAdminUser();
776 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
779 'purposeid' => $purposes[0]->get('id'),
780 'categoryid' => $categories[0]->get('id'),
781 'contextlevel' => CONTEXT_SYSTEM
,
783 $contextlevel = api
::set_contextlevel($record);
784 $this->assertInstanceOf('\tool_dataprivacy\contextlevel', $contextlevel);
785 $this->assertEquals($record->contextlevel
, $contextlevel->get('contextlevel'));
786 $this->assertEquals($record->purposeid
, $contextlevel->get('purposeid'));
787 $this->assertEquals($record->categoryid
, $contextlevel->get('categoryid'));
790 $record->purposeid
= $purposes[1]->get('id');
791 $contextlevel = api
::set_contextlevel($record);
792 $this->assertEquals($record->contextlevel
, $contextlevel->get('contextlevel'));
793 $this->assertEquals($record->purposeid
, $contextlevel->get('purposeid'));
794 $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxlevel'));
796 $record->contextlevel
= CONTEXT_USER
;
797 $contextlevel = api
::set_contextlevel($record);
798 $this->assertEquals(2, $DB->count_records('tool_dataprivacy_ctxlevel'));
802 * Test effective context levels purpose and category defaults.
806 public function test_effective_contextlevel_defaults() {
807 $this->setAdminUser();
809 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
811 list($purposeid, $categoryid) = data_registry
::get_effective_default_contextlevel_purpose_and_category(CONTEXT_SYSTEM
);
812 $this->assertEquals(false, $purposeid);
813 $this->assertEquals(false, $categoryid);
815 list($purposevar, $categoryvar) = data_registry
::var_names_from_context(
816 \context_helper
::get_class_for_level(CONTEXT_SYSTEM
)
818 set_config($purposevar, $purposes[0]->get('id'), 'tool_dataprivacy');
820 list($purposeid, $categoryid) = data_registry
::get_effective_default_contextlevel_purpose_and_category(CONTEXT_SYSTEM
);
821 $this->assertEquals($purposes[0]->get('id'), $purposeid);
822 $this->assertEquals(false, $categoryid);
824 // Course inherits from system if not defined.
825 list($purposeid, $categoryid) = data_registry
::get_effective_default_contextlevel_purpose_and_category(CONTEXT_COURSE
);
826 $this->assertEquals($purposes[0]->get('id'), $purposeid);
827 $this->assertEquals(false, $categoryid);
829 // Course defined values should have preference.
830 list($purposevar, $categoryvar) = data_registry
::var_names_from_context(
831 \context_helper
::get_class_for_level(CONTEXT_COURSE
)
833 set_config($purposevar, $purposes[1]->get('id'), 'tool_dataprivacy');
834 set_config($categoryvar, $categories[0]->get('id'), 'tool_dataprivacy');
836 list($purposeid, $categoryid) = data_registry
::get_effective_default_contextlevel_purpose_and_category(CONTEXT_COURSE
);
837 $this->assertEquals($purposes[1]->get('id'), $purposeid);
838 $this->assertEquals($categories[0]->get('id'), $categoryid);
840 // Context level defaults are also allowed to be set to 'inherit'.
841 set_config($purposevar, context_instance
::INHERIT
, 'tool_dataprivacy');
843 list($purposeid, $categoryid) = data_registry
::get_effective_default_contextlevel_purpose_and_category(CONTEXT_COURSE
);
844 $this->assertEquals($purposes[0]->get('id'), $purposeid);
845 $this->assertEquals($categories[0]->get('id'), $categoryid);
847 list($purposeid, $categoryid) = data_registry
::get_effective_default_contextlevel_purpose_and_category(CONTEXT_MODULE
);
848 $this->assertEquals($purposes[0]->get('id'), $purposeid);
849 $this->assertEquals($categories[0]->get('id'), $categoryid);
853 * Test effective contextlevel return.
857 public function test_effective_contextlevel() {
858 $this->setAdminUser();
860 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
862 // Set the system context level to purpose 1.
864 'contextlevel' => CONTEXT_SYSTEM
,
865 'purposeid' => $purposes[1]->get('id'),
866 'categoryid' => $categories[1]->get('id'),
868 api
::set_contextlevel($record);
870 $purpose = api
::get_effective_contextlevel_purpose(CONTEXT_SYSTEM
);
871 $this->assertEquals($purposes[1]->get('id'), $purpose->get('id'));
873 // Value 'not set' will get the default value for the context level. For context level defaults
874 // both 'not set' and 'inherit' result in inherit, so the parent context (system) default
875 // will be retrieved.
876 $purpose = api
::get_effective_contextlevel_purpose(CONTEXT_USER
);
877 $this->assertEquals($purposes[1]->get('id'), $purpose->get('id'));
879 // The behaviour forcing an inherit from context system should result in the same effective
881 $record->purposeid
= context_instance
::INHERIT
;
882 $record->contextlevel
= CONTEXT_USER
;
883 api
::set_contextlevel($record);
884 $purpose = api
::get_effective_contextlevel_purpose(CONTEXT_USER
);
885 $this->assertEquals($purposes[1]->get('id'), $purpose->get('id'));
887 $record->purposeid
= $purposes[2]->get('id');
888 $record->contextlevel
= CONTEXT_USER
;
889 api
::set_contextlevel($record);
891 $purpose = api
::get_effective_contextlevel_purpose(CONTEXT_USER
);
892 $this->assertEquals($purposes[2]->get('id'), $purpose->get('id'));
894 // Only system and user allowed.
895 $this->expectException(coding_exception
::class);
896 $record->contextlevel
= CONTEXT_COURSE
;
897 $record->purposeid
= $purposes[1]->get('id');
898 api
::set_contextlevel($record);
902 * Test effective context purposes and categories.
906 public function test_effective_context() {
907 $this->setAdminUser();
909 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
911 // Define system defaults (all context levels below will inherit).
912 list($purposevar, $categoryvar) = data_registry
::var_names_from_context(
913 \context_helper
::get_class_for_level(CONTEXT_SYSTEM
)
915 set_config($purposevar, $purposes[0]->get('id'), 'tool_dataprivacy');
916 set_config($categoryvar, $categories[0]->get('id'), 'tool_dataprivacy');
918 // Define course defaults.
919 list($purposevar, $categoryvar) = data_registry
::var_names_from_context(
920 \context_helper
::get_class_for_level(CONTEXT_COURSE
)
922 set_config($purposevar, $purposes[1]->get('id'), 'tool_dataprivacy');
923 set_config($categoryvar, $categories[1]->get('id'), 'tool_dataprivacy');
925 $course0context = \context_course
::instance($courses[0]->id
);
926 $course1context = \context_course
::instance($courses[1]->id
);
927 $mod0context = \context_module
::instance($modules[0]->cmid
);
928 $mod1context = \context_module
::instance($modules[1]->cmid
);
930 // Set course instance values.
932 'contextid' => $course0context->id
,
933 'purposeid' => $purposes[1]->get('id'),
934 'categoryid' => $categories[2]->get('id'),
936 api
::set_context_instance($record);
937 $category = api
::get_effective_context_category($course0context);
938 $this->assertEquals($record->categoryid
, $category->get('id'));
940 // Module instances get the context level default if nothing specified.
941 $category = api
::get_effective_context_category($mod0context);
942 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
944 // Module instances get the parent context category if they inherit.
945 $record->contextid
= $mod0context->id
;
946 $record->categoryid
= context_instance
::INHERIT
;
947 api
::set_context_instance($record);
948 $category = api
::get_effective_context_category($mod0context);
949 $this->assertEquals($categories[2]->get('id'), $category->get('id'));
951 // The $forcedvalue param allows us to override the actual value (method php-docs for more info).
952 $category = api
::get_effective_context_category($mod0context, $categories[1]->get('id'));
953 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
954 $category = api
::get_effective_context_category($mod0context, $categories[0]->get('id'));
955 $this->assertEquals($categories[0]->get('id'), $category->get('id'));
957 // Module instances get the parent context category if they inherit; in
958 // this case the parent context category is not set so it should use the
959 // context level default (see 'Define course defaults' above).
960 $record->contextid
= $mod1context->id
;
961 $record->categoryid
= context_instance
::INHERIT
;
962 api
::set_context_instance($record);
963 $category = api
::get_effective_context_category($mod1context);
964 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
966 // User instances use the value set at user context level instead of the user default.
968 // User defaults to cat 0 and user context level to 1.
969 list($purposevar, $categoryvar) = data_registry
::var_names_from_context(
970 \context_helper
::get_class_for_level(CONTEXT_USER
)
972 set_config($purposevar, $purposes[0]->get('id'), 'tool_dataprivacy');
973 set_config($categoryvar, $categories[0]->get('id'), 'tool_dataprivacy');
974 $usercontextlevel = (object)[
975 'contextlevel' => CONTEXT_USER
,
976 'purposeid' => $purposes[1]->get('id'),
977 'categoryid' => $categories[1]->get('id'),
979 api
::set_contextlevel($usercontextlevel);
981 $newuser = $this->getDataGenerator()->create_user();
982 $usercontext = \context_user
::instance($newuser->id
);
983 $category = api
::get_effective_context_category($usercontext);
984 $this->assertEquals($categories[1]->get('id'), $category->get('id'));
988 * Tests the deletion of expired contexts.
992 public function test_expired_context_deletion() {
995 $this->setAdminUser();
997 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
999 $course0context = \context_course
::instance($courses[0]->id
);
1000 $course1context = \context_course
::instance($courses[1]->id
);
1002 $expiredcontext0 = api
::create_expired_context($course0context->id
);
1003 $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired'));
1004 $expiredcontext1 = api
::create_expired_context($course1context->id
);
1005 $this->assertEquals(2, $DB->count_records('tool_dataprivacy_ctxexpired'));
1007 api
::delete_expired_context($expiredcontext0->get('id'));
1008 $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired'));
1012 * Tests the status of expired contexts.
1016 public function test_expired_context_status() {
1019 $this->setAdminUser();
1021 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories();
1023 $course0context = \context_course
::instance($courses[0]->id
);
1025 $expiredcontext = api
::create_expired_context($course0context->id
);
1028 $this->assertEquals(expired_context
::STATUS_EXPIRED
, $expiredcontext->get('status'));
1030 api
::set_expired_context_status($expiredcontext, expired_context
::STATUS_APPROVED
);
1031 $this->assertEquals(expired_context
::STATUS_APPROVED
, $expiredcontext->get('status'));
1035 * Creates test purposes and categories.
1039 protected function add_purposes_and_categories() {
1041 $purpose1 = api
::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'PT1H']);
1042 $purpose2 = api
::create_purpose((object)['name' => 'p2', 'retentionperiod' => 'PT2H']);
1043 $purpose3 = api
::create_purpose((object)['name' => 'p3', 'retentionperiod' => 'PT3H']);
1045 $cat1 = api
::create_category((object)['name' => 'a']);
1046 $cat2 = api
::create_category((object)['name' => 'b']);
1047 $cat3 = api
::create_category((object)['name' => 'c']);
1049 $course1 = $this->getDataGenerator()->create_course();
1050 $course2 = $this->getDataGenerator()->create_course();
1052 $module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1));
1053 $module2 = $this->getDataGenerator()->create_module('resource', array('course' => $course2));
1056 [$purpose1, $purpose2, $purpose3],
1057 [$cat1, $cat2, $cat3],
1058 [$course1, $course2],
1059 [$module1, $module2]