Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
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 namespace tool_dataprivacy; 18 19 use core\invalid_persistent_exception; 20 use core\task\manager; 21 use testing_data_generator; 22 use tool_dataprivacy\local\helper; 23 use tool_dataprivacy\task\process_data_request_task; 24 use tool_dataprivacy\task\initiate_data_request_task; 25 26 /** 27 * API tests. 28 * 29 * @package tool_dataprivacy 30 * @covers \tool_dataprivacy\api 31 * @copyright 2018 Jun Pataleta 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class api_test extends \advanced_testcase { 35 36 /** 37 * Ensure that the check_can_manage_data_registry function fails cap testing when a user without capabilities is 38 * tested with the default context. 39 */ 40 public function test_check_can_manage_data_registry_admin() { 41 $this->resetAfterTest(); 42 43 $this->setAdminUser(); 44 // Technically this actually returns void, but assertNull will suffice to avoid a pointless test. 45 $this->assertNull(api::check_can_manage_data_registry()); 46 } 47 48 /** 49 * Ensure that the check_can_manage_data_registry function fails cap testing when a user without capabilities is 50 * tested with the default context. 51 */ 52 public function test_check_can_manage_data_registry_without_cap_default() { 53 $this->resetAfterTest(); 54 55 $user = $this->getDataGenerator()->create_user(); 56 $this->setUser($user); 57 58 $this->expectException(\required_capability_exception::class); 59 api::check_can_manage_data_registry(); 60 } 61 62 /** 63 * Ensure that the check_can_manage_data_registry function fails cap testing when a user without capabilities is 64 * tested with the default context. 65 */ 66 public function test_check_can_manage_data_registry_without_cap_system() { 67 $this->resetAfterTest(); 68 69 $user = $this->getDataGenerator()->create_user(); 70 $this->setUser($user); 71 72 $this->expectException(\required_capability_exception::class); 73 api::check_can_manage_data_registry(\context_system::instance()->id); 74 } 75 76 /** 77 * Ensure that the check_can_manage_data_registry function fails cap testing when a user without capabilities is 78 * tested with the default context. 79 */ 80 public function test_check_can_manage_data_registry_without_cap_own_user() { 81 $this->resetAfterTest(); 82 83 $user = $this->getDataGenerator()->create_user(); 84 $this->setUser($user); 85 86 $this->expectException(\required_capability_exception::class); 87 api::check_can_manage_data_registry(\context_user::instance($user->id)->id); 88 } 89 90 /** 91 * Test for api::update_request_status(). 92 */ 93 public function test_update_request_status() { 94 $this->resetAfterTest(); 95 96 $generator = new testing_data_generator(); 97 $s1 = $generator->create_user(); 98 $this->setUser($s1); 99 100 // Create the sample data request. 101 $datarequest = api::create_data_request($s1->id, api::DATAREQUEST_TYPE_EXPORT); 102 103 $requestid = $datarequest->get('id'); 104 105 // Update with a comment. 106 $comment = 'This is an example of a comment'; 107 $result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 0, $comment); 108 $this->assertTrue($result); 109 $datarequest = new data_request($requestid); 110 $this->assertStringEndsWith($comment, $datarequest->get('dpocomment')); 111 112 // Update with a comment which will be trimmed. 113 $result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 0, ' '); 114 $this->assertTrue($result); 115 $datarequest = new data_request($requestid); 116 $this->assertStringEndsWith($comment, $datarequest->get('dpocomment')); 117 118 // Update with a comment. 119 $secondcomment = ' - More comments - '; 120 $result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 0, $secondcomment); 121 $this->assertTrue($result); 122 $datarequest = new data_request($requestid); 123 $this->assertMatchesRegularExpression("/.*{$comment}.*{$secondcomment}/s", $datarequest->get('dpocomment')); 124 125 // Update with a valid status. 126 $result = api::update_request_status($requestid, api::DATAREQUEST_STATUS_DOWNLOAD_READY); 127 $this->assertTrue($result); 128 129 // Fetch the request record again. 130 $datarequest = new data_request($requestid); 131 $this->assertEquals(api::DATAREQUEST_STATUS_DOWNLOAD_READY, $datarequest->get('status')); 132 133 // Update with an invalid status. 134 $this->expectException(invalid_persistent_exception::class); 135 api::update_request_status($requestid, -1); 136 } 137 138 /** 139 * Test for api::get_site_dpos() when there are no users with the DPO role. 140 */ 141 public function test_get_site_dpos_no_dpos() { 142 $this->resetAfterTest(); 143 144 $admin = get_admin(); 145 146 $dpos = api::get_site_dpos(); 147 $this->assertCount(1, $dpos); 148 $dpo = reset($dpos); 149 $this->assertEquals($admin->id, $dpo->id); 150 } 151 152 /** 153 * Test for api::get_site_dpos() when there are no users with the DPO role. 154 */ 155 public function test_get_site_dpos() { 156 global $DB; 157 158 $this->resetAfterTest(); 159 160 $generator = new testing_data_generator(); 161 $u1 = $generator->create_user(); 162 $u2 = $generator->create_user(); 163 164 $context = \context_system::instance(); 165 166 // Give the manager role with the capability to manage data requests. 167 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); 168 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true); 169 // Assign u1 as a manager. 170 role_assign($managerroleid, $u1->id, $context->id); 171 172 // Give the editing teacher role with the capability to manage data requests. 173 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher')); 174 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $editingteacherroleid, $context->id, true); 175 // Assign u1 as an editing teacher as well. 176 role_assign($editingteacherroleid, $u1->id, $context->id); 177 // Assign u2 as an editing teacher. 178 role_assign($editingteacherroleid, $u2->id, $context->id); 179 180 // Only map the manager role to the DPO role. 181 set_config('dporoles', $managerroleid, 'tool_dataprivacy'); 182 183 $dpos = api::get_site_dpos(); 184 $this->assertCount(1, $dpos); 185 $dpo = reset($dpos); 186 $this->assertEquals($u1->id, $dpo->id); 187 } 188 189 /** 190 * Test for \tool_dataprivacy\api::get_assigned_privacy_officer_roles(). 191 */ 192 public function test_get_assigned_privacy_officer_roles() { 193 global $DB; 194 195 $this->resetAfterTest(); 196 197 // Erroneously set the manager roles as the PO, even if it doesn't have the managedatarequests capability yet. 198 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); 199 set_config('dporoles', $managerroleid, 'tool_dataprivacy'); 200 // Get the assigned PO roles when nothing has been set yet. 201 $roleids = api::get_assigned_privacy_officer_roles(); 202 // Confirm that the returned list is empty. 203 $this->assertEmpty($roleids); 204 205 $context = \context_system::instance(); 206 207 // Give the manager role with the capability to manage data requests. 208 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true); 209 210 // Give the editing teacher role with the capability to manage data requests. 211 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher')); 212 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $editingteacherroleid, $context->id, true); 213 214 // Get the non-editing teacher role ID. 215 $teacherroleid = $DB->get_field('role', 'id', array('shortname' => 'teacher')); 216 217 // Erroneously map the manager and the non-editing teacher roles to the PO role. 218 $badconfig = $managerroleid . ',' . $teacherroleid; 219 set_config('dporoles', $badconfig, 'tool_dataprivacy'); 220 221 // Get the assigned PO roles. 222 $roleids = api::get_assigned_privacy_officer_roles(); 223 224 // There should only be one PO role. 225 $this->assertCount(1, $roleids); 226 // Confirm it contains the manager role. 227 $this->assertContainsEquals($managerroleid, $roleids); 228 // And it does not contain the editing teacher role. 229 $this->assertNotContainsEquals($editingteacherroleid, $roleids); 230 } 231 232 /** 233 * Test for api::approve_data_request(). 234 */ 235 public function test_approve_data_request() { 236 global $DB; 237 238 $this->resetAfterTest(); 239 240 $generator = new testing_data_generator(); 241 $s1 = $generator->create_user(); 242 $u1 = $generator->create_user(); 243 244 $context = \context_system::instance(); 245 246 // Manager role. 247 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); 248 // Give the manager role with the capability to manage data requests. 249 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true); 250 // Assign u1 as a manager. 251 role_assign($managerroleid, $u1->id, $context->id); 252 253 // Map the manager role to the DPO role. 254 set_config('dporoles', $managerroleid, 'tool_dataprivacy'); 255 256 // Create the sample data request. 257 $this->setUser($s1); 258 $datarequest = api::create_data_request($s1->id, api::DATAREQUEST_TYPE_EXPORT); 259 $requestid = $datarequest->get('id'); 260 261 // Make this ready for approval. 262 api::update_request_status($requestid, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 263 264 $this->setUser($u1); 265 $result = api::approve_data_request($requestid); 266 $this->assertTrue($result); 267 $datarequest = new data_request($requestid); 268 $this->assertEquals($u1->id, $datarequest->get('dpo')); 269 $this->assertEquals(api::DATAREQUEST_STATUS_APPROVED, $datarequest->get('status')); 270 271 // Test adhoc task creation. 272 $adhoctasks = manager::get_adhoc_tasks(process_data_request_task::class); 273 $this->assertCount(1, $adhoctasks); 274 } 275 276 /** 277 * Test for api::approve_data_request() when allow filtering of exports by course. 278 */ 279 public function test_approve_data_request_with_allow_filtering() { 280 global $DB; 281 $this->resetAfterTest(); 282 set_config('allowfiltering', 1, 'tool_dataprivacy'); 283 $this->setAdminUser(); 284 285 $generator = new testing_data_generator(); 286 $s1 = $generator->create_user(); 287 $u1 = $generator->create_user(); 288 289 $context = \context_system::instance(); 290 291 // Manager role. 292 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); 293 // Give the manager role with the capability to manage data requests. 294 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true); 295 // Assign u1 as a manager. 296 role_assign($managerroleid, $u1->id, $context->id); 297 298 // Map the manager role to the DPO role. 299 set_config('dporoles', $managerroleid, 'tool_dataprivacy'); 300 301 $course = $this->getDataGenerator()->create_course([]); 302 303 $coursecontext1 = \context_course::instance($course->id); 304 305 $this->getDataGenerator()->enrol_user($s1->id, $course->id, 'student'); 306 307 $datarequest = api::create_data_request($s1->id, api::DATAREQUEST_TYPE_EXPORT); 308 $requestid = $datarequest->get('id'); 309 ob_start(); 310 $this->runAdhocTasks('tool_dataprivacy\task\initiate_data_request_task'); 311 ob_end_clean(); 312 313 $this->setUser($u1); 314 $result = api::approve_data_request($requestid, [$coursecontext1]); 315 $this->assertTrue($result); 316 $datarequest = new data_request($requestid); 317 $this->assertEquals($u1->id, $datarequest->get('dpo')); 318 $this->assertEquals(api::DATAREQUEST_STATUS_APPROVED, $datarequest->get('status')); 319 320 // Test adhoc task creation. 321 $adhoctasks = manager::get_adhoc_tasks(process_data_request_task::class); 322 $this->assertCount(1, $adhoctasks); 323 } 324 325 /** 326 * Test for api::approve_data_request() when called by a user who doesn't have the DPO role. 327 */ 328 public function test_approve_data_request_non_dpo_user() { 329 $this->resetAfterTest(); 330 331 $generator = new testing_data_generator(); 332 $student = $generator->create_user(); 333 $teacher = $generator->create_user(); 334 335 // Create the sample data request. 336 $this->setUser($student); 337 $datarequest = api::create_data_request($student->id, api::DATAREQUEST_TYPE_EXPORT); 338 339 $requestid = $datarequest->get('id'); 340 341 // Login as a user without DPO role. 342 $this->setUser($teacher); 343 $this->expectException(\required_capability_exception::class); 344 api::approve_data_request($requestid); 345 } 346 347 /** 348 * Test for api::add_request_contexts_with_status(). 349 */ 350 public function test_add_request_contexts_with_status() { 351 global $DB; 352 $this->resetAfterTest(); 353 set_config('allowfiltering', 1, 'tool_dataprivacy'); 354 355 $this->setAdminUser(); 356 $user = $this->getDataGenerator()->create_user(); 357 358 $course = $this->getDataGenerator()->create_course(['startdate' => time() - YEARSECS, 'enddate' => time() - YEARSECS]); 359 $coursecontext = \context_course::instance($course->id); 360 361 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 362 363 // Create the initial contextlist. 364 $initialcollection = new \core_privacy\local\request\contextlist_collection($user->id); 365 366 $contextlist = new \core_privacy\local\request\contextlist(); 367 $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $coursecontext->id]); 368 $contextlist->set_component('tool_dataprivacy'); 369 $initialcollection->add_contextlist($contextlist); 370 371 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT); 372 $requestid = $datarequest->get('id'); 373 374 ob_start(); 375 api::add_request_contexts_with_status($initialcollection, $requestid, contextlist_context::STATUS_PENDING); 376 ob_end_clean(); 377 378 $result = $DB->get_record('tool_dataprivacy_ctxlst_ctx', ['contextid' => $coursecontext->id]); 379 $this->assertEquals($result->status, contextlist_context::STATUS_PENDING); 380 381 $result1 = $DB->get_field('tool_dataprivacy_rqst_ctxlst', 'requestid', ['contextlistid' => $result->contextlistid]); 382 $this->assertEquals($result1, $requestid); 383 } 384 385 /** 386 * Test that deletion requests for the primary admin are rejected 387 */ 388 public function test_reject_data_deletion_request_primary_admin() { 389 $this->resetAfterTest(); 390 $this->setAdminUser(); 391 392 $datarequest = api::create_data_request(get_admin()->id, api::DATAREQUEST_TYPE_DELETE); 393 394 // Approve the request and execute the ad-hoc process task. 395 ob_start(); 396 api::approve_data_request($datarequest->get('id')); 397 $this->runAdhocTasks('\tool_dataprivacy\task\process_data_request_task'); 398 ob_end_clean(); 399 400 $request = api::get_request($datarequest->get('id')); 401 $this->assertEquals(api::DATAREQUEST_STATUS_REJECTED, $request->get('status')); 402 403 // Confirm they weren't deleted. 404 $user = \core_user::get_user($request->get('userid')); 405 \core_user::require_active_user($user); 406 } 407 408 /** 409 * Test for api::can_contact_dpo() 410 */ 411 public function test_can_contact_dpo() { 412 $this->resetAfterTest(); 413 414 // Default ('contactdataprotectionofficer' is disabled by default). 415 $this->assertFalse(api::can_contact_dpo()); 416 417 // Enable. 418 set_config('contactdataprotectionofficer', 1, 'tool_dataprivacy'); 419 $this->assertTrue(api::can_contact_dpo()); 420 421 // Disable again. 422 set_config('contactdataprotectionofficer', 0, 'tool_dataprivacy'); 423 $this->assertFalse(api::can_contact_dpo()); 424 } 425 426 /** 427 * Test for api::can_manage_data_requests() 428 */ 429 public function test_can_manage_data_requests() { 430 global $DB; 431 432 $this->resetAfterTest(); 433 434 // No configured site DPOs yet. 435 $admin = get_admin(); 436 $this->assertTrue(api::can_manage_data_requests($admin->id)); 437 438 $generator = new testing_data_generator(); 439 $dpo = $generator->create_user(); 440 $nondpocapable = $generator->create_user(); 441 $nondpoincapable = $generator->create_user(); 442 443 $context = \context_system::instance(); 444 445 // Manager role. 446 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); 447 // Give the manager role with the capability to manage data requests. 448 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true); 449 // Assign u1 as a manager. 450 role_assign($managerroleid, $dpo->id, $context->id); 451 452 // Editing teacher role. 453 $editingteacherroleid = $DB->get_field('role', 'id', array('shortname' => 'editingteacher')); 454 // Give the editing teacher role with the capability to manage data requests. 455 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true); 456 // Assign u2 as an editing teacher. 457 role_assign($editingteacherroleid, $nondpocapable->id, $context->id); 458 459 // Map only the manager role to the DPO role. 460 set_config('dporoles', $managerroleid, 'tool_dataprivacy'); 461 462 // User with capability and has DPO role. 463 $this->assertTrue(api::can_manage_data_requests($dpo->id)); 464 // User with capability but has no DPO role. 465 $this->assertFalse(api::can_manage_data_requests($nondpocapable->id)); 466 // User without the capability and has no DPO role. 467 $this->assertFalse(api::can_manage_data_requests($nondpoincapable->id)); 468 } 469 470 /** 471 * Test that a user who has no capability to make any data requests for children cannot create data requests for any 472 * other user. 473 */ 474 public function test_can_create_data_request_for_user_no() { 475 $this->resetAfterTest(); 476 477 $parent = $this->getDataGenerator()->create_user(); 478 $otheruser = $this->getDataGenerator()->create_user(); 479 480 $this->setUser($parent); 481 $this->assertFalse(api::can_create_data_request_for_user($otheruser->id)); 482 } 483 484 /** 485 * Test that a user who has the capability to make any data requests for one other user cannot create data requests 486 * for any other user. 487 */ 488 public function test_can_create_data_request_for_user_some() { 489 $this->resetAfterTest(); 490 491 $parent = $this->getDataGenerator()->create_user(); 492 $child = $this->getDataGenerator()->create_user(); 493 $otheruser = $this->getDataGenerator()->create_user(); 494 495 $systemcontext = \context_system::instance(); 496 $parentrole = $this->getDataGenerator()->create_role(); 497 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 498 role_assign($parentrole, $parent->id, \context_user::instance($child->id)); 499 500 $this->setUser($parent); 501 $this->assertFalse(api::can_create_data_request_for_user($otheruser->id)); 502 } 503 504 /** 505 * Test that a user who has the capability to make any data requests for one other user cannot create data requests 506 * for any other user. 507 */ 508 public function test_can_create_data_request_for_user_own_child() { 509 $this->resetAfterTest(); 510 511 $parent = $this->getDataGenerator()->create_user(); 512 $child = $this->getDataGenerator()->create_user(); 513 514 $systemcontext = \context_system::instance(); 515 $parentrole = $this->getDataGenerator()->create_role(); 516 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 517 role_assign($parentrole, $parent->id, \context_user::instance($child->id)); 518 519 $this->setUser($parent); 520 $this->assertTrue(api::can_create_data_request_for_user($child->id)); 521 } 522 523 /** 524 * Test that a user who has no capability to make any data requests for children cannot create data requests for any 525 * other user. 526 */ 527 public function test_require_can_create_data_request_for_user_no() { 528 $this->resetAfterTest(); 529 530 $parent = $this->getDataGenerator()->create_user(); 531 $otheruser = $this->getDataGenerator()->create_user(); 532 533 $this->setUser($parent); 534 $this->expectException('required_capability_exception'); 535 api::require_can_create_data_request_for_user($otheruser->id); 536 } 537 538 /** 539 * Test that a user who has the capability to make any data requests for one other user cannot create data requests 540 * for any other user. 541 */ 542 public function test_require_can_create_data_request_for_user_some() { 543 $this->resetAfterTest(); 544 545 $parent = $this->getDataGenerator()->create_user(); 546 $child = $this->getDataGenerator()->create_user(); 547 $otheruser = $this->getDataGenerator()->create_user(); 548 549 $systemcontext = \context_system::instance(); 550 $parentrole = $this->getDataGenerator()->create_role(); 551 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 552 role_assign($parentrole, $parent->id, \context_user::instance($child->id)); 553 554 $this->setUser($parent); 555 $this->expectException('required_capability_exception'); 556 api::require_can_create_data_request_for_user($otheruser->id); 557 } 558 559 /** 560 * Test that a user who has the capability to make any data requests for one other user cannot create data requests 561 * for any other user. 562 */ 563 public function test_require_can_create_data_request_for_user_own_child() { 564 $this->resetAfterTest(); 565 566 $parent = $this->getDataGenerator()->create_user(); 567 $child = $this->getDataGenerator()->create_user(); 568 569 $systemcontext = \context_system::instance(); 570 $parentrole = $this->getDataGenerator()->create_role(); 571 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 572 role_assign($parentrole, $parent->id, \context_user::instance($child->id)); 573 574 $this->setUser($parent); 575 $this->assertTrue(api::require_can_create_data_request_for_user($child->id)); 576 } 577 578 /** 579 * Test for api::can_download_data_request_for_user() 580 */ 581 public function test_can_download_data_request_for_user() { 582 $this->resetAfterTest(); 583 584 $generator = $this->getDataGenerator(); 585 586 // Three victims. 587 $victim1 = $generator->create_user(); 588 $victim2 = $generator->create_user(); 589 $victim3 = $generator->create_user(); 590 591 // Assign a user as victim 1's parent. 592 $systemcontext = \context_system::instance(); 593 $parentrole = $generator->create_role(); 594 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 595 $parent = $generator->create_user(); 596 role_assign($parentrole, $parent->id, \context_user::instance($victim1->id)); 597 598 // Assign another user as data access wonder woman. 599 $wonderrole = $generator->create_role(); 600 assign_capability('tool/dataprivacy:downloadallrequests', CAP_ALLOW, $wonderrole, $systemcontext); 601 $staff = $generator->create_user(); 602 role_assign($wonderrole, $staff->id, $systemcontext); 603 604 // Finally, victim 3 has been naughty; stop them accessing their own data. 605 $naughtyrole = $generator->create_role(); 606 assign_capability('tool/dataprivacy:downloadownrequest', CAP_PROHIBIT, $naughtyrole, $systemcontext); 607 role_assign($naughtyrole, $victim3->id, $systemcontext); 608 609 // Victims 1 and 2 can access their own data, regardless of who requested it. 610 $this->assertTrue(api::can_download_data_request_for_user($victim1->id, $victim1->id, $victim1->id)); 611 $this->assertTrue(api::can_download_data_request_for_user($victim2->id, $staff->id, $victim2->id)); 612 613 // Victim 3 cannot access his own data. 614 $this->assertFalse(api::can_download_data_request_for_user($victim3->id, $victim3->id, $victim3->id)); 615 616 // Victims 1 and 2 cannot access another victim's data. 617 $this->assertFalse(api::can_download_data_request_for_user($victim2->id, $victim1->id, $victim1->id)); 618 $this->assertFalse(api::can_download_data_request_for_user($victim1->id, $staff->id, $victim2->id)); 619 620 // Staff can access everyone's data. 621 $this->assertTrue(api::can_download_data_request_for_user($victim1->id, $victim1->id, $staff->id)); 622 $this->assertTrue(api::can_download_data_request_for_user($victim2->id, $staff->id, $staff->id)); 623 $this->assertTrue(api::can_download_data_request_for_user($victim3->id, $staff->id, $staff->id)); 624 625 // Parent can access victim 1's data only if they requested it. 626 $this->assertTrue(api::can_download_data_request_for_user($victim1->id, $parent->id, $parent->id)); 627 $this->assertFalse(api::can_download_data_request_for_user($victim1->id, $staff->id, $parent->id)); 628 $this->assertFalse(api::can_download_data_request_for_user($victim2->id, $parent->id, $parent->id)); 629 } 630 631 /** 632 * Data provider for data request creation tests. 633 * 634 * @return array 635 */ 636 public function data_request_creation_provider() { 637 return [ 638 'Export request by user, automatic approval off' => [ 639 false, api::DATAREQUEST_TYPE_EXPORT, 'automaticdataexportapproval', false, 0, 640 api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 0, 0 641 ], 642 'Export request by user, automatic approval on' => [ 643 false, api::DATAREQUEST_TYPE_EXPORT, 'automaticdataexportapproval', true, 0, 644 api::DATAREQUEST_STATUS_APPROVED, 1 , 0 645 ], 646 'Export request by PO, automatic approval off' => [ 647 true, api::DATAREQUEST_TYPE_EXPORT, 'automaticdataexportapproval', false, 0, 648 api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 0, 0 649 ], 650 'Export request by PO, automatic approval off, allow filtering of exports by course' => [ 651 true, api::DATAREQUEST_TYPE_EXPORT, 'automaticdataexportapproval', false, 0, 652 api::DATAREQUEST_STATUS_PENDING, 0, 1 653 ], 654 'Export request by PO, automatic approval on' => [ 655 true, api::DATAREQUEST_TYPE_EXPORT, 'automaticdataexportapproval', true, 'dpo', 656 api::DATAREQUEST_STATUS_APPROVED, 1, 0 657 ], 658 'Delete request by user, automatic approval off' => [ 659 false, api::DATAREQUEST_TYPE_DELETE, 'automaticdatadeletionapproval', false, 0, 660 api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 0, 0 661 ], 662 'Delete request by user, automatic approval on' => [ 663 false, api::DATAREQUEST_TYPE_DELETE, 'automaticdatadeletionapproval', true, 0, 664 api::DATAREQUEST_STATUS_APPROVED, 1, 0 665 ], 666 'Delete request by PO, automatic approval off' => [ 667 true, api::DATAREQUEST_TYPE_DELETE, 'automaticdatadeletionapproval', false, 0, 668 api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 0, 0 669 ], 670 'Delete request by PO, automatic approval on' => [ 671 true, api::DATAREQUEST_TYPE_DELETE, 'automaticdatadeletionapproval', true, 'dpo', 672 api::DATAREQUEST_STATUS_APPROVED, 1, 0 673 ], 674 ]; 675 } 676 677 /** 678 * Test for api::create_data_request() 679 * 680 * @dataProvider data_request_creation_provider 681 * @param bool $asprivacyofficer Whether the request is made as the Privacy Officer or the user itself. 682 * @param string $type The data request type. 683 * @param string $setting The automatic approval setting. 684 * @param bool $automaticapproval Whether automatic data request approval is turned on or not. 685 * @param int|string $expecteddpoval The expected value for the 'dpo' field. 'dpo' means we'd the expected value would be the 686 * user ID of the privacy officer which happens in the case where a PO requests on behalf of 687 * someone else and automatic data request approval is turned on. 688 * @param int $expectedstatus The expected status of the data request. 689 * @param int $expectedtaskcount The number of expected queued data requests tasks. 690 * @param bool $allowfiltering Whether allow filtering of exports by course turn on or off. 691 * @throws coding_exception 692 * @throws invalid_persistent_exception 693 */ 694 public function test_create_data_request( 695 $asprivacyofficer, 696 $type, 697 $setting, 698 $automaticapproval, 699 $expecteddpoval, 700 $expectedstatus, 701 $expectedtaskcount, 702 $allowfiltering, 703 ) { 704 global $USER; 705 706 $this->resetAfterTest(); 707 708 $generator = new testing_data_generator(); 709 $user = $generator->create_user(); 710 $comment = 'sample comment'; 711 712 // Login. 713 if ($asprivacyofficer) { 714 $this->setAdminUser(); 715 } else { 716 $this->setUser($user->id); 717 } 718 719 // Set the automatic data request approval setting value. 720 set_config($setting, $automaticapproval, 'tool_dataprivacy'); 721 722 // If set to 'dpo' use the currently logged-in user's ID (which should be the admin user's ID). 723 if ($expecteddpoval === 'dpo') { 724 $expecteddpoval = $USER->id; 725 } 726 if ($allowfiltering) { 727 set_config('allowfiltering', 1, 'tool_dataprivacy'); 728 } 729 730 // Test data request creation. 731 $datarequest = api::create_data_request($user->id, $type, $comment); 732 $this->assertEquals($user->id, $datarequest->get('userid')); 733 $this->assertEquals($USER->id, $datarequest->get('requestedby')); 734 $this->assertEquals($expecteddpoval, $datarequest->get('dpo')); 735 $this->assertEquals($type, $datarequest->get('type')); 736 $this->assertEquals($expectedstatus, $datarequest->get('status')); 737 $this->assertEquals($comment, $datarequest->get('comments')); 738 $this->assertEquals($automaticapproval, $datarequest->get('systemapproved')); 739 740 // Test number of queued data request tasks. 741 $datarequesttasks = manager::get_adhoc_tasks(process_data_request_task::class); 742 $this->assertCount($expectedtaskcount, $datarequesttasks); 743 744 if ($allowfiltering) { 745 // Test number of queued initiate data request tasks. 746 $datarequesttasks = manager::get_adhoc_tasks(initiate_data_request_task::class); 747 $this->assertCount(1, $datarequesttasks); 748 } 749 } 750 751 /** 752 * Test for api::create_data_request() made by a parent. 753 */ 754 public function test_create_data_request_by_parent() { 755 global $DB; 756 757 $this->resetAfterTest(); 758 759 $generator = new testing_data_generator(); 760 $user = $generator->create_user(); 761 $parent = $generator->create_user(); 762 $comment = 'sample comment'; 763 764 // Get the teacher role pretend it's the parent roles ;). 765 $systemcontext = \context_system::instance(); 766 $usercontext = \context_user::instance($user->id); 767 $parentroleid = $DB->get_field('role', 'id', array('shortname' => 'teacher')); 768 // Give the manager role with the capability to manage data requests. 769 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentroleid, $systemcontext->id, true); 770 // Assign the parent to user. 771 role_assign($parentroleid, $parent->id, $usercontext->id); 772 773 // Login as the user's parent. 774 $this->setUser($parent); 775 776 // Test data request creation. 777 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 778 $this->assertEquals($user->id, $datarequest->get('userid')); 779 $this->assertEquals($parent->id, $datarequest->get('requestedby')); 780 $this->assertEquals(0, $datarequest->get('dpo')); 781 $this->assertEquals(api::DATAREQUEST_TYPE_EXPORT, $datarequest->get('type')); 782 $this->assertEquals(api::DATAREQUEST_STATUS_AWAITING_APPROVAL, $datarequest->get('status')); 783 $this->assertEquals($comment, $datarequest->get('comments')); 784 } 785 786 /** 787 * Test for api::deny_data_request() 788 */ 789 public function test_deny_data_request() { 790 $this->resetAfterTest(); 791 792 $generator = new testing_data_generator(); 793 $user = $generator->create_user(); 794 $comment = 'sample comment'; 795 796 // Login as user. 797 $this->setUser($user->id); 798 799 // Test data request creation. 800 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 801 802 // Login as the admin (default DPO when no one is set). 803 $this->setAdminUser(); 804 805 // Make this ready for approval. 806 api::update_request_status($datarequest->get('id'), api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 807 808 // Deny the data request. 809 $result = api::deny_data_request($datarequest->get('id')); 810 $this->assertTrue($result); 811 } 812 813 /** 814 * Data provider for \tool_dataprivacy_api_testcase::test_get_data_requests(). 815 * 816 * @return array 817 */ 818 public function get_data_requests_provider() { 819 $completeonly = [api::DATAREQUEST_STATUS_COMPLETE, api::DATAREQUEST_STATUS_DOWNLOAD_READY, api::DATAREQUEST_STATUS_DELETED]; 820 $completeandcancelled = array_merge($completeonly, [api::DATAREQUEST_STATUS_CANCELLED]); 821 822 return [ 823 // Own data requests. 824 ['user', false, $completeonly], 825 // Non-DPO fetching all requets. 826 ['user', true, $completeonly], 827 // Admin fetching all completed and cancelled requests. 828 ['dpo', true, $completeandcancelled], 829 // Admin fetching all completed requests. 830 ['dpo', true, $completeonly], 831 // Guest fetching all requests. 832 ['guest', true, $completeonly], 833 ]; 834 } 835 836 /** 837 * Test for api::get_data_requests() 838 * 839 * @dataProvider get_data_requests_provider 840 * @param string $usertype The type of the user logging in. 841 * @param boolean $fetchall Whether to fetch all records. 842 * @param int[] $statuses Status filters. 843 */ 844 public function test_get_data_requests($usertype, $fetchall, $statuses) { 845 $this->resetAfterTest(); 846 847 $generator = new testing_data_generator(); 848 $user1 = $generator->create_user(); 849 $user2 = $generator->create_user(); 850 $user3 = $generator->create_user(); 851 $user4 = $generator->create_user(); 852 $user5 = $generator->create_user(); 853 $users = [$user1, $user2, $user3, $user4, $user5]; 854 855 switch ($usertype) { 856 case 'user': 857 $loggeduser = $user1; 858 break; 859 case 'dpo': 860 $loggeduser = get_admin(); 861 break; 862 case 'guest': 863 $loggeduser = guest_user(); 864 break; 865 } 866 867 $comment = 'Data %s request comment by user %d'; 868 $exportstring = helper::get_shortened_request_type_string(api::DATAREQUEST_TYPE_EXPORT); 869 $deletionstring = helper::get_shortened_request_type_string(api::DATAREQUEST_TYPE_DELETE); 870 // Make a data requests for the users. 871 foreach ($users as $user) { 872 $this->setUser($user); 873 api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, sprintf($comment, $exportstring, $user->id)); 874 api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT, sprintf($comment, $deletionstring, $user->id)); 875 } 876 877 // Log in as the target user. 878 $this->setUser($loggeduser); 879 // Get records count based on the filters. 880 $userid = $loggeduser->id; 881 if ($fetchall) { 882 $userid = 0; 883 } 884 $count = api::get_data_requests_count($userid); 885 if (api::is_site_dpo($loggeduser->id)) { 886 // DPOs should see all the requests. 887 $this->assertEquals(count($users) * 2, $count); 888 } else { 889 if (empty($userid)) { 890 // There should be no data requests for this user available. 891 $this->assertEquals(0, $count); 892 } else { 893 // There should be only one (request with pending status). 894 $this->assertEquals(2, $count); 895 } 896 } 897 // Get data requests. 898 $requests = api::get_data_requests($userid); 899 // The number of requests should match the count. 900 $this->assertCount($count, $requests); 901 902 // Test filtering by status. 903 if ($count && !empty($statuses)) { 904 $filteredcount = api::get_data_requests_count($userid, $statuses); 905 // There should be none as they are all pending. 906 $this->assertEquals(0, $filteredcount); 907 $filteredrequests = api::get_data_requests($userid, $statuses); 908 $this->assertCount($filteredcount, $filteredrequests); 909 910 $statuscounts = []; 911 foreach ($statuses as $stat) { 912 $statuscounts[$stat] = 0; 913 } 914 $numstatus = count($statuses); 915 // Get all requests with status filter and update statuses, randomly. 916 foreach ($requests as $request) { 917 if (rand(0, 1)) { 918 continue; 919 } 920 921 if ($numstatus > 1) { 922 $index = rand(0, $numstatus - 1); 923 $status = $statuses[$index]; 924 } else { 925 $status = reset($statuses); 926 } 927 $statuscounts[$status]++; 928 api::update_request_status($request->get('id'), $status); 929 } 930 $total = array_sum($statuscounts); 931 $filteredcount = api::get_data_requests_count($userid, $statuses); 932 $this->assertEquals($total, $filteredcount); 933 $filteredrequests = api::get_data_requests($userid, $statuses); 934 $this->assertCount($filteredcount, $filteredrequests); 935 // Confirm the filtered requests match the status filter(s). 936 foreach ($filteredrequests as $request) { 937 $this->assertContainsEquals($request->get('status'), $statuses); 938 } 939 940 if ($numstatus > 1) { 941 // Fetch by individual status to check the numbers match. 942 foreach ($statuses as $status) { 943 $filteredcount = api::get_data_requests_count($userid, [$status]); 944 $this->assertEquals($statuscounts[$status], $filteredcount); 945 $filteredrequests = api::get_data_requests($userid, [$status]); 946 $this->assertCount($filteredcount, $filteredrequests); 947 } 948 } 949 } 950 } 951 952 /** 953 * Test for api::get_approved_contextlist_collection_for_request. 954 */ 955 public function test_get_approved_contextlist_collection_for_request() { 956 $this->resetAfterTest(); 957 set_config('allowfiltering', 1, 'tool_dataprivacy'); 958 $this->setAdminUser(); 959 960 $user = $this->getDataGenerator()->create_user(); 961 962 $course = $this->getDataGenerator()->create_course([]); 963 964 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); 965 966 $generator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 967 968 $record = new \stdClass(); 969 $record->course = $course->id; 970 $record->userid = $user->id; 971 $record->forum = $forum->id; 972 $generator->create_discussion($record); 973 974 $generator->create_discussion($record); 975 976 $coursecontext1 = \context_course::instance($course->id); 977 978 $forumcontext1 = \context_module::instance($forum->cmid); 979 980 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 981 982 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT); 983 984 ob_start(); 985 $this->runAdhocTasks('tool_dataprivacy\task\initiate_data_request_task'); 986 ob_end_clean(); 987 988 api::approve_contexts_belonging_to_request($datarequest->get('id'), [$coursecontext1->id]); 989 $contextlistcollection = api::get_approved_contextlist_collection_for_request($datarequest); 990 $approvecontexts = []; 991 foreach ($contextlistcollection->get_contextlists() as $contextlist) { 992 foreach ($contextlist->get_contextids() as $contextid) { 993 $approvecontexts[] = $contextid; 994 } 995 } 996 $this->assertContains(strval($coursecontext1->id), $approvecontexts); 997 $this->assertContains(strval($forumcontext1->id), $approvecontexts); 998 } 999 1000 /** 1001 * Data provider for test_has_ongoing_request. 1002 */ 1003 public function status_provider() { 1004 return [ 1005 [api::DATAREQUEST_STATUS_AWAITING_APPROVAL, true], 1006 [api::DATAREQUEST_STATUS_APPROVED, true], 1007 [api::DATAREQUEST_STATUS_PROCESSING, true], 1008 [api::DATAREQUEST_STATUS_COMPLETE, false], 1009 [api::DATAREQUEST_STATUS_CANCELLED, false], 1010 [api::DATAREQUEST_STATUS_REJECTED, false], 1011 [api::DATAREQUEST_STATUS_DOWNLOAD_READY, false], 1012 [api::DATAREQUEST_STATUS_EXPIRED, false], 1013 [api::DATAREQUEST_STATUS_DELETED, false], 1014 ]; 1015 } 1016 1017 /** 1018 * Test for api::has_ongoing_request() 1019 * 1020 * @dataProvider status_provider 1021 * @param int $status The request status. 1022 * @param bool $expected The expected result. 1023 */ 1024 public function test_has_ongoing_request($status, $expected) { 1025 $this->resetAfterTest(); 1026 1027 $generator = new testing_data_generator(); 1028 $user1 = $generator->create_user(); 1029 1030 // Make a data request as user 1. 1031 $this->setUser($user1); 1032 $request = api::create_data_request($user1->id, api::DATAREQUEST_TYPE_EXPORT); 1033 // Set the status. 1034 api::update_request_status($request->get('id'), $status); 1035 1036 // Check if this request is ongoing. 1037 $result = api::has_ongoing_request($user1->id, api::DATAREQUEST_TYPE_EXPORT); 1038 $this->assertEquals($expected, $result); 1039 } 1040 1041 /** 1042 * Test for api::is_active() 1043 * 1044 * @dataProvider status_provider 1045 * @param int $status The request status 1046 * @param bool $expected The expected result 1047 */ 1048 public function test_is_active($status, $expected) { 1049 // Check if this request is ongoing. 1050 $result = api::is_active($status); 1051 $this->assertEquals($expected, $result); 1052 } 1053 1054 /** 1055 * Test for api::is_site_dpo() 1056 */ 1057 public function test_is_site_dpo() { 1058 global $DB; 1059 1060 $this->resetAfterTest(); 1061 1062 // No configured site DPOs yet. 1063 $admin = get_admin(); 1064 $this->assertTrue(api::is_site_dpo($admin->id)); 1065 1066 $generator = new testing_data_generator(); 1067 $dpo = $generator->create_user(); 1068 $nondpo = $generator->create_user(); 1069 1070 $context = \context_system::instance(); 1071 1072 // Manager role. 1073 $managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager')); 1074 // Give the manager role with the capability to manage data requests. 1075 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $managerroleid, $context->id, true); 1076 // Assign u1 as a manager. 1077 role_assign($managerroleid, $dpo->id, $context->id); 1078 1079 // Map only the manager role to the DPO role. 1080 set_config('dporoles', $managerroleid, 'tool_dataprivacy'); 1081 1082 // User is a DPO. 1083 $this->assertTrue(api::is_site_dpo($dpo->id)); 1084 // User is not a DPO. 1085 $this->assertFalse(api::is_site_dpo($nondpo->id)); 1086 } 1087 1088 /** 1089 * Data provider function for test_notify_dpo 1090 * 1091 * @return array 1092 */ 1093 public function notify_dpo_provider() { 1094 return [ 1095 [false, api::DATAREQUEST_TYPE_EXPORT, 'requesttypeexport', 'Export my user data'], 1096 [false, api::DATAREQUEST_TYPE_DELETE, 'requesttypedelete', 'Delete my user data'], 1097 [false, api::DATAREQUEST_TYPE_OTHERS, 'requesttypeothers', 'Nothing. Just wanna say hi'], 1098 [true, api::DATAREQUEST_TYPE_EXPORT, 'requesttypeexport', 'Admin export data of another user'], 1099 ]; 1100 } 1101 1102 /** 1103 * Test for api::notify_dpo() 1104 * 1105 * @dataProvider notify_dpo_provider 1106 * @param bool $byadmin Whether the admin requests data on behalf of the user 1107 * @param int $type The request type 1108 * @param string $typestringid The request lang string identifier 1109 * @param string $comments The requestor's message to the DPO. 1110 */ 1111 public function test_notify_dpo($byadmin, $type, $typestringid, $comments) { 1112 $this->resetAfterTest(); 1113 1114 $generator = new testing_data_generator(); 1115 $user1 = $generator->create_user(); 1116 // Let's just use admin as DPO (It's the default if not set). 1117 $dpo = get_admin(); 1118 if ($byadmin) { 1119 $this->setAdminUser(); 1120 $requestedby = $dpo; 1121 } else { 1122 $this->setUser($user1); 1123 $requestedby = $user1; 1124 } 1125 1126 // Make a data request for user 1. 1127 $request = api::create_data_request($user1->id, $type, $comments); 1128 1129 $sink = $this->redirectMessages(); 1130 $messageid = api::notify_dpo($dpo, $request); 1131 $this->assertNotFalse($messageid); 1132 $messages = $sink->get_messages(); 1133 $this->assertCount(1, $messages); 1134 $message = reset($messages); 1135 1136 // Check some of the message properties. 1137 $this->assertEquals($requestedby->id, $message->useridfrom); 1138 $this->assertEquals($dpo->id, $message->useridto); 1139 $typestring = get_string($typestringid, 'tool_dataprivacy'); 1140 $subject = get_string('datarequestemailsubject', 'tool_dataprivacy', $typestring); 1141 $this->assertEquals($subject, $message->subject); 1142 $this->assertEquals('tool_dataprivacy', $message->component); 1143 $this->assertEquals('contactdataprotectionofficer', $message->eventtype); 1144 $this->assertStringContainsString(fullname($dpo), $message->fullmessage); 1145 $this->assertStringContainsString(fullname($user1), $message->fullmessage); 1146 } 1147 1148 /** 1149 * Test data purposes CRUD actions. 1150 * 1151 * @return null 1152 */ 1153 public function test_purpose_crud() { 1154 $this->resetAfterTest(); 1155 1156 $this->setAdminUser(); 1157 1158 // Add. 1159 $purpose = api::create_purpose((object)[ 1160 'name' => 'bbb', 1161 'description' => '<b>yeah</b>', 1162 'descriptionformat' => 1, 1163 'retentionperiod' => 'PT1M', 1164 'lawfulbases' => 'gdpr_art_6_1_a,gdpr_art_6_1_c,gdpr_art_6_1_e' 1165 ]); 1166 $this->assertInstanceOf('\tool_dataprivacy\purpose', $purpose); 1167 $this->assertEquals('bbb', $purpose->get('name')); 1168 $this->assertEquals('PT1M', $purpose->get('retentionperiod')); 1169 $this->assertEquals('gdpr_art_6_1_a,gdpr_art_6_1_c,gdpr_art_6_1_e', $purpose->get('lawfulbases')); 1170 1171 // Update. 1172 $purpose->set('retentionperiod', 'PT2M'); 1173 $purpose = api::update_purpose($purpose->to_record()); 1174 $this->assertEquals('PT2M', $purpose->get('retentionperiod')); 1175 1176 // Retrieve. 1177 $purpose = api::create_purpose((object)['name' => 'aaa', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a']); 1178 $purposes = api::get_purposes(); 1179 $this->assertCount(2, $purposes); 1180 $this->assertEquals('aaa', $purposes[0]->get('name')); 1181 $this->assertEquals('bbb', $purposes[1]->get('name')); 1182 1183 // Delete. 1184 api::delete_purpose($purposes[0]->get('id')); 1185 $this->assertCount(1, api::get_purposes()); 1186 api::delete_purpose($purposes[1]->get('id')); 1187 $this->assertCount(0, api::get_purposes()); 1188 } 1189 1190 /** 1191 * Test data categories CRUD actions. 1192 * 1193 * @return null 1194 */ 1195 public function test_category_crud() { 1196 $this->resetAfterTest(); 1197 1198 $this->setAdminUser(); 1199 1200 // Add. 1201 $category = api::create_category((object)[ 1202 'name' => 'bbb', 1203 'description' => '<b>yeah</b>', 1204 'descriptionformat' => 1 1205 ]); 1206 $this->assertInstanceOf('\tool_dataprivacy\category', $category); 1207 $this->assertEquals('bbb', $category->get('name')); 1208 1209 // Update. 1210 $category->set('name', 'bcd'); 1211 $category = api::update_category($category->to_record()); 1212 $this->assertEquals('bcd', $category->get('name')); 1213 1214 // Retrieve. 1215 $category = api::create_category((object)['name' => 'aaa']); 1216 $categories = api::get_categories(); 1217 $this->assertCount(2, $categories); 1218 $this->assertEquals('aaa', $categories[0]->get('name')); 1219 $this->assertEquals('bcd', $categories[1]->get('name')); 1220 1221 // Delete. 1222 api::delete_category($categories[0]->get('id')); 1223 $this->assertCount(1, api::get_categories()); 1224 api::delete_category($categories[1]->get('id')); 1225 $this->assertCount(0, api::get_categories()); 1226 } 1227 1228 /** 1229 * Test context instances. 1230 * 1231 * @return null 1232 */ 1233 public function test_context_instances() { 1234 global $DB; 1235 1236 $this->resetAfterTest(); 1237 1238 $this->setAdminUser(); 1239 1240 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories(); 1241 1242 $coursecontext1 = \context_course::instance($courses[0]->id); 1243 $coursecontext2 = \context_course::instance($courses[1]->id); 1244 1245 $record1 = (object)['contextid' => $coursecontext1->id, 'purposeid' => $purposes[0]->get('id'), 1246 'categoryid' => $categories[0]->get('id')]; 1247 $contextinstance1 = api::set_context_instance($record1); 1248 1249 $record2 = (object)['contextid' => $coursecontext2->id, 'purposeid' => $purposes[1]->get('id'), 1250 'categoryid' => $categories[1]->get('id')]; 1251 $contextinstance2 = api::set_context_instance($record2); 1252 1253 $this->assertCount(2, $DB->get_records('tool_dataprivacy_ctxinstance')); 1254 1255 api::unset_context_instance($contextinstance1); 1256 $this->assertCount(1, $DB->get_records('tool_dataprivacy_ctxinstance')); 1257 1258 $update = (object)['id' => $contextinstance2->get('id'), 'contextid' => $coursecontext2->id, 1259 'purposeid' => $purposes[0]->get('id'), 'categoryid' => $categories[0]->get('id')]; 1260 $contextinstance2 = api::set_context_instance($update); 1261 $this->assertCount(1, $DB->get_records('tool_dataprivacy_ctxinstance')); 1262 } 1263 1264 /** 1265 * Test contextlevel. 1266 * 1267 * @return null 1268 */ 1269 public function test_contextlevel() { 1270 global $DB; 1271 1272 $this->resetAfterTest(); 1273 1274 $this->setAdminUser(); 1275 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories(); 1276 1277 $record = (object)[ 1278 'purposeid' => $purposes[0]->get('id'), 1279 'categoryid' => $categories[0]->get('id'), 1280 'contextlevel' => CONTEXT_SYSTEM, 1281 ]; 1282 $contextlevel = api::set_contextlevel($record); 1283 $this->assertInstanceOf('\tool_dataprivacy\contextlevel', $contextlevel); 1284 $this->assertEquals($record->contextlevel, $contextlevel->get('contextlevel')); 1285 $this->assertEquals($record->purposeid, $contextlevel->get('purposeid')); 1286 $this->assertEquals($record->categoryid, $contextlevel->get('categoryid')); 1287 1288 // Now update it. 1289 $record->purposeid = $purposes[1]->get('id'); 1290 $contextlevel = api::set_contextlevel($record); 1291 $this->assertEquals($record->contextlevel, $contextlevel->get('contextlevel')); 1292 $this->assertEquals($record->purposeid, $contextlevel->get('purposeid')); 1293 $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxlevel')); 1294 1295 $record->contextlevel = CONTEXT_USER; 1296 $contextlevel = api::set_contextlevel($record); 1297 $this->assertEquals(2, $DB->count_records('tool_dataprivacy_ctxlevel')); 1298 } 1299 1300 /** 1301 * Test effective context levels purpose and category defaults. 1302 * 1303 * @return null 1304 */ 1305 public function test_effective_contextlevel_defaults() { 1306 $this->setAdminUser(); 1307 1308 $this->resetAfterTest(); 1309 1310 list($purposes, $categories, $courses, $modules) = $this->add_purposes_and_categories(); 1311 1312 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_SYSTEM); 1313 $this->assertEquals(false, $purposeid); 1314 $this->assertEquals(false, $categoryid); 1315 1316 list($purposevar, $categoryvar) = data_registry::var_names_from_context( 1317 \context_helper::get_class_for_level(CONTEXT_SYSTEM) 1318 ); 1319 set_config($purposevar, $purposes[0]->get('id'), 'tool_dataprivacy'); 1320 1321 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_SYSTEM); 1322 $this->assertEquals($purposes[0]->get('id'), $purposeid); 1323 $this->assertEquals(false, $categoryid); 1324 1325 // Course defined values should have preference. 1326 list($purposevar, $categoryvar) = data_registry::var_names_from_context( 1327 \context_helper::get_class_for_level(CONTEXT_COURSE) 1328 ); 1329 set_config($purposevar, $purposes[1]->get('id'), 'tool_dataprivacy'); 1330 set_config($categoryvar, $categories[0]->get('id'), 'tool_dataprivacy'); 1331 1332 list($purposeid, $categoryid) = data_registry::get_effective_default_contextlevel_purpose_and_category(CONTEXT_COURSE); 1333 $this->assertEquals($purposes[1]->get('id'), $purposeid); 1334 $this->assertEquals($categories[0]->get('id'), $categoryid); 1335 1336 // Context level defaults are also allowed to be set to 'inherit'. 1337 set_config($purposevar, context_instance::INHERIT, 'tool_dataprivacy'); 1338 } 1339 1340 /** 1341 * Ensure that when nothing is configured, all values return false. 1342 */ 1343 public function test_get_effective_contextlevel_unset() { 1344 // Before setup, get_effective_contextlevel_purpose will return false. 1345 $this->assertFalse(api::get_effective_contextlevel_category(CONTEXT_SYSTEM)); 1346 $this->assertFalse(api::get_effective_contextlevel_purpose(CONTEXT_SYSTEM)); 1347 1348 $this->assertFalse(api::get_effective_contextlevel_category(CONTEXT_USER)); 1349 $this->assertFalse(api::get_effective_contextlevel_purpose(CONTEXT_USER)); 1350 } 1351 1352 /** 1353 * Ensure that when nothing is configured, all values return false. 1354 */ 1355 public function test_get_effective_context_unset() { 1356 // Before setup, get_effective_contextlevel_purpose will return false. 1357 $this->assertFalse(api::get_effective_context_category(\context_system::instance())); 1358 $this->assertFalse(api::get_effective_context_purpose(\context_system::instance())); 1359 } 1360 1361 /** 1362 * Ensure that fetching the effective value for context levels is only available to system, and user context levels. 1363 * 1364 * @dataProvider invalid_effective_contextlevel_provider 1365 * @param int $contextlevel 1366 */ 1367 public function test_set_contextlevel_invalid_contextlevels($contextlevel) { 1368 1369 $this->expectException(\coding_exception::class); 1370 api::set_contextlevel((object) [ 1371 'contextlevel' => $contextlevel, 1372 ]); 1373 1374 } 1375 1376 /** 1377 * Test effective contextlevel return. 1378 */ 1379 public function test_effective_contextlevel() { 1380 $this->resetAfterTest(); 1381 1382 // Set the initial purpose and category. 1383 $purpose1 = api::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'PT1H', 'lawfulbases' => 'gdpr_art_6_1_a']); 1384 $category1 = api::create_category((object)['name' => 'a']); 1385 api::set_contextlevel((object)[ 1386 'contextlevel' => CONTEXT_SYSTEM, 1387 'purposeid' => $purpose1->get('id'), 1388 'categoryid' => $category1->get('id'), 1389 ]); 1390 1391 $this->assertEquals($purpose1, api::get_effective_contextlevel_purpose(CONTEXT_SYSTEM)); 1392 $this->assertEquals($category1, api::get_effective_contextlevel_category(CONTEXT_SYSTEM)); 1393 1394 // The user context inherits from the system context when not set. 1395 $this->assertEquals($purpose1, api::get_effective_contextlevel_purpose(CONTEXT_USER)); 1396 $this->assertEquals($category1, api::get_effective_contextlevel_category(CONTEXT_USER)); 1397 1398 // Forcing the behaviour to inherit will have the same result. 1399 api::set_contextlevel((object) [ 1400 'contextlevel' => CONTEXT_USER, 1401 'purposeid' => context_instance::INHERIT, 1402 'categoryid' => context_instance::INHERIT, 1403 ]); 1404 $this->assertEquals($purpose1, api::get_effective_contextlevel_purpose(CONTEXT_USER)); 1405 $this->assertEquals($category1, api::get_effective_contextlevel_category(CONTEXT_USER)); 1406 1407 // Setting specific values will override the inheritance behaviour. 1408 $purpose2 = api::create_purpose((object)['name' => 'p2', 'retentionperiod' => 'PT2H', 'lawfulbases' => 'gdpr_art_6_1_a']); 1409 $category2 = api::create_category((object)['name' => 'b']); 1410 // Set the system context level to purpose 1. 1411 api::set_contextlevel((object) [ 1412 'contextlevel' => CONTEXT_USER, 1413 'purposeid' => $purpose2->get('id'), 1414 'categoryid' => $category2->get('id'), 1415 ]); 1416 1417 $this->assertEquals($purpose2, api::get_effective_contextlevel_purpose(CONTEXT_USER)); 1418 $this->assertEquals($category2, api::get_effective_contextlevel_category(CONTEXT_USER)); 1419 } 1420 1421 /** 1422 * Ensure that fetching the effective value for context levels is only available to system, and user context levels. 1423 * 1424 * @dataProvider invalid_effective_contextlevel_provider 1425 * @param int $contextlevel 1426 */ 1427 public function test_effective_contextlevel_invalid_contextlevels($contextlevel) { 1428 $this->resetAfterTest(); 1429 1430 $purpose1 = api::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'PT1H', 'lawfulbases' => 'gdpr_art_6_1_a']); 1431 $category1 = api::create_category((object)['name' => 'a']); 1432 api::set_contextlevel((object)[ 1433 'contextlevel' => CONTEXT_SYSTEM, 1434 'purposeid' => $purpose1->get('id'), 1435 'categoryid' => $category1->get('id'), 1436 ]); 1437 1438 $this->expectException(\coding_exception::class); 1439 api::get_effective_contextlevel_purpose($contextlevel); 1440 } 1441 1442 /** 1443 * Data provider for invalid contextlevel fetchers. 1444 */ 1445 public function invalid_effective_contextlevel_provider() { 1446 return [ 1447 [CONTEXT_COURSECAT], 1448 [CONTEXT_COURSE], 1449 [CONTEXT_MODULE], 1450 [CONTEXT_BLOCK], 1451 ]; 1452 } 1453 1454 /** 1455 * Ensure that context inheritance works up the context tree. 1456 */ 1457 public function test_effective_context_inheritance() { 1458 $this->resetAfterTest(); 1459 1460 $systemdata = $this->create_and_set_purpose_for_contextlevel('PT1S', CONTEXT_SYSTEM); 1461 1462 /* 1463 * System 1464 * - Cat 1465 * - Subcat 1466 * - Course 1467 * - Forum 1468 * - User 1469 * - User block 1470 */ 1471 $cat = $this->getDataGenerator()->create_category(); 1472 $subcat = $this->getDataGenerator()->create_category(['parent' => $cat->id]); 1473 $course = $this->getDataGenerator()->create_course(['category' => $subcat->id]); 1474 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); 1475 list(, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum'); 1476 1477 $user = $this->getDataGenerator()->create_user(); 1478 1479 $contextsystem = \context_system::instance(); 1480 $contextcat = \context_coursecat::instance($cat->id); 1481 $contextsubcat = \context_coursecat::instance($subcat->id); 1482 $contextcourse = \context_course::instance($course->id); 1483 $contextforum = \context_module::instance($forumcm->id); 1484 $contextuser = \context_user::instance($user->id); 1485 1486 // Initially everything is set to Inherit. 1487 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1488 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat)); 1489 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1")); 1490 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "0")); 1491 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat)); 1492 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "-1")); 1493 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "0")); 1494 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse)); 1495 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "-1")); 1496 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "0")); 1497 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum)); 1498 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "-1")); 1499 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "0")); 1500 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser)); 1501 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "-1")); 1502 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "0")); 1503 1504 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1505 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat)); 1506 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1")); 1507 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "0")); 1508 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat)); 1509 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "-1")); 1510 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "0")); 1511 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse)); 1512 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "-1")); 1513 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "0")); 1514 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum)); 1515 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "-1")); 1516 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "0")); 1517 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextuser)); 1518 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextuser, "-1")); 1519 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextuser, "0")); 1520 1521 // When actively set, user will use the specified value. 1522 $userdata = $this->create_and_set_purpose_for_contextlevel('PT1S', CONTEXT_USER); 1523 1524 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1525 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat)); 1526 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1")); 1527 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "0")); 1528 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat)); 1529 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "-1")); 1530 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "0")); 1531 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse)); 1532 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "-1")); 1533 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "0")); 1534 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum)); 1535 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "-1")); 1536 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "0")); 1537 $this->assertEquals($userdata->purpose, api::get_effective_context_purpose($contextuser)); 1538 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "-1")); 1539 1540 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1541 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat)); 1542 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1")); 1543 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "0")); 1544 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat)); 1545 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "-1")); 1546 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "0")); 1547 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse)); 1548 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "-1")); 1549 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "0")); 1550 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum)); 1551 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "-1")); 1552 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "0")); 1553 $this->assertEquals($userdata->category, api::get_effective_context_category($contextuser)); 1554 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "-1")); 1555 1556 // Set a context for the top category. 1557 $catpurpose = new purpose(0, (object) [ 1558 'name' => 'Purpose', 1559 'retentionperiod' => 'P1D', 1560 'lawfulbases' => 'gdpr_art_6_1_a', 1561 ]); 1562 $catpurpose->save(); 1563 $catcategory = new category(0, (object) ['name' => 'Category']); 1564 $catcategory->save(); 1565 api::set_context_instance((object) [ 1566 'contextid' => $contextcat->id, 1567 'purposeid' => $catpurpose->get('id'), 1568 'categoryid' => $catcategory->get('id'), 1569 ]); 1570 1571 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1572 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat)); 1573 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1")); 1574 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0")); 1575 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat)); 1576 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1")); 1577 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "0")); 1578 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcourse)); 1579 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcourse, "-1")); 1580 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcourse, "0")); 1581 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum)); 1582 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum, "-1")); 1583 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum, "0")); 1584 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum, "0")); 1585 1586 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1587 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat)); 1588 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1")); 1589 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0")); 1590 $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat)); 1591 $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1")); 1592 $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "0")); 1593 $this->assertEquals($catcategory, api::get_effective_context_category($contextcourse)); 1594 $this->assertEquals($catcategory, api::get_effective_context_category($contextcourse, "-1")); 1595 $this->assertEquals($catcategory, api::get_effective_context_category($contextcourse, "0")); 1596 $this->assertEquals($catcategory, api::get_effective_context_category($contextforum)); 1597 $this->assertEquals($catcategory, api::get_effective_context_category($contextforum, "-1")); 1598 $this->assertEquals($catcategory, api::get_effective_context_category($contextforum, "0")); 1599 1600 // Set a context for the sub category. 1601 $subcatpurpose = new purpose(0, (object) [ 1602 'name' => 'Purpose', 1603 'retentionperiod' => 'P1D', 1604 'lawfulbases' => 'gdpr_art_6_1_a', 1605 ]); 1606 $subcatpurpose->save(); 1607 $subcatcategory = new category(0, (object) ['name' => 'Category']); 1608 $subcatcategory->save(); 1609 api::set_context_instance((object) [ 1610 'contextid' => $contextsubcat->id, 1611 'purposeid' => $subcatpurpose->get('id'), 1612 'categoryid' => $subcatcategory->get('id'), 1613 ]); 1614 1615 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1616 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat)); 1617 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1")); 1618 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0")); 1619 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat)); 1620 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1")); 1621 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat, "0")); 1622 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse)); 1623 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "-1")); 1624 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "0")); 1625 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextforum)); 1626 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextforum, "-1")); 1627 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextforum, "0")); 1628 1629 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1630 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat)); 1631 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1")); 1632 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0")); 1633 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat)); 1634 $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1")); 1635 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat, "0")); 1636 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse)); 1637 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "-1")); 1638 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "0")); 1639 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextforum)); 1640 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextforum, "-1")); 1641 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextforum, "0")); 1642 1643 // Set a context for the course. 1644 $coursepurpose = new purpose(0, (object) [ 1645 'name' => 'Purpose', 1646 'retentionperiod' => 'P1D', 1647 'lawfulbases' => 'gdpr_art_6_1_a', 1648 ]); 1649 $coursepurpose->save(); 1650 $coursecategory = new category(0, (object) ['name' => 'Category']); 1651 $coursecategory->save(); 1652 api::set_context_instance((object) [ 1653 'contextid' => $contextcourse->id, 1654 'purposeid' => $coursepurpose->get('id'), 1655 'categoryid' => $coursecategory->get('id'), 1656 ]); 1657 1658 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1659 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat)); 1660 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1")); 1661 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0")); 1662 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat)); 1663 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1")); 1664 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat, "0")); 1665 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse)); 1666 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "-1")); 1667 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse, "0")); 1668 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum)); 1669 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum, "-1")); 1670 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum, "0")); 1671 1672 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1673 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat)); 1674 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1")); 1675 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0")); 1676 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat)); 1677 $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1")); 1678 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat, "0")); 1679 $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse)); 1680 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "-1")); 1681 $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse, "0")); 1682 $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum)); 1683 $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum, "-1")); 1684 $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum, "0")); 1685 1686 // Set a context for the forum. 1687 $forumpurpose = new purpose(0, (object) [ 1688 'name' => 'Purpose', 1689 'retentionperiod' => 'P1D', 1690 'lawfulbases' => 'gdpr_art_6_1_a', 1691 ]); 1692 $forumpurpose->save(); 1693 $forumcategory = new category(0, (object) ['name' => 'Category']); 1694 $forumcategory->save(); 1695 api::set_context_instance((object) [ 1696 'contextid' => $contextforum->id, 1697 'purposeid' => $forumpurpose->get('id'), 1698 'categoryid' => $forumcategory->get('id'), 1699 ]); 1700 1701 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1702 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat)); 1703 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1")); 1704 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0")); 1705 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat)); 1706 $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1")); 1707 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat, "0")); 1708 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse)); 1709 $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "-1")); 1710 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse, "0")); 1711 $this->assertEquals($forumpurpose, api::get_effective_context_purpose($contextforum)); 1712 $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum, "-1")); 1713 $this->assertEquals($forumpurpose, api::get_effective_context_purpose($contextforum, "0")); 1714 1715 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1716 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat)); 1717 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1")); 1718 $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0")); 1719 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat)); 1720 $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1")); 1721 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat, "0")); 1722 $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse)); 1723 $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "-1")); 1724 $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse, "0")); 1725 $this->assertEquals($forumcategory, api::get_effective_context_category($contextforum)); 1726 $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum, "-1")); 1727 $this->assertEquals($forumcategory, api::get_effective_context_category($contextforum, "0")); 1728 } 1729 1730 /** 1731 * Ensure that context inheritance works up the context tree when inherit values are explicitly set at the 1732 * contextlevel. 1733 * 1734 * Although it should not be possible to set hard INHERIT values at this level, there may be legacy data which still 1735 * contains this. 1736 */ 1737 public function test_effective_context_inheritance_explicitly_set() { 1738 $this->resetAfterTest(); 1739 1740 $systemdata = $this->create_and_set_purpose_for_contextlevel('PT1S', CONTEXT_SYSTEM); 1741 1742 /* 1743 * System 1744 * - Cat 1745 * - Subcat 1746 * - Course 1747 * - Forum 1748 * - User 1749 * - User block 1750 */ 1751 $cat = $this->getDataGenerator()->create_category(); 1752 $subcat = $this->getDataGenerator()->create_category(['parent' => $cat->id]); 1753 $course = $this->getDataGenerator()->create_course(['category' => $subcat->id]); 1754 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); 1755 list(, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum'); 1756 1757 $contextsystem = \context_system::instance(); 1758 $contextcat = \context_coursecat::instance($cat->id); 1759 $contextsubcat = \context_coursecat::instance($subcat->id); 1760 $contextcourse = \context_course::instance($course->id); 1761 $contextforum = \context_module::instance($forumcm->id); 1762 1763 // Initially everything is set to Inherit. 1764 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1765 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat)); 1766 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat)); 1767 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse)); 1768 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum)); 1769 1770 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1771 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat)); 1772 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat)); 1773 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse)); 1774 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum)); 1775 1776 // Set a default value of inherit for CONTEXT_COURSECAT. 1777 $classname = \context_helper::get_class_for_level(CONTEXT_COURSECAT); 1778 list($purposevar, $categoryvar) = data_registry::var_names_from_context($classname); 1779 set_config($purposevar, '-1', 'tool_dataprivacy'); 1780 set_config($categoryvar, '-1', 'tool_dataprivacy'); 1781 1782 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1783 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat)); 1784 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat)); 1785 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse)); 1786 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum)); 1787 1788 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1789 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat)); 1790 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat)); 1791 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse)); 1792 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum)); 1793 1794 // Set a default value of inherit for CONTEXT_COURSE. 1795 $classname = \context_helper::get_class_for_level(CONTEXT_COURSE); 1796 list($purposevar, $categoryvar) = data_registry::var_names_from_context($classname); 1797 set_config($purposevar, '-1', 'tool_dataprivacy'); 1798 set_config($categoryvar, '-1', 'tool_dataprivacy'); 1799 1800 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1801 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat)); 1802 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat)); 1803 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse)); 1804 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum)); 1805 1806 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1807 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat)); 1808 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat)); 1809 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse)); 1810 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum)); 1811 1812 // Set a default value of inherit for CONTEXT_MODULE. 1813 $classname = \context_helper::get_class_for_level(CONTEXT_MODULE); 1814 list($purposevar, $categoryvar) = data_registry::var_names_from_context($classname); 1815 set_config($purposevar, '-1', 'tool_dataprivacy'); 1816 set_config($categoryvar, '-1', 'tool_dataprivacy'); 1817 1818 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem)); 1819 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat)); 1820 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat)); 1821 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse)); 1822 $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum)); 1823 1824 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem)); 1825 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat)); 1826 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat)); 1827 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse)); 1828 $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum)); 1829 } 1830 1831 /** 1832 * Creates test purposes and categories. 1833 * 1834 * @return null 1835 */ 1836 protected function add_purposes_and_categories() { 1837 $this->resetAfterTest(); 1838 1839 $purpose1 = api::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'PT1H', 'lawfulbases' => 'gdpr_art_6_1_a']); 1840 $purpose2 = api::create_purpose((object)['name' => 'p2', 'retentionperiod' => 'PT2H', 'lawfulbases' => 'gdpr_art_6_1_b']); 1841 $purpose3 = api::create_purpose((object)['name' => 'p3', 'retentionperiod' => 'PT3H', 'lawfulbases' => 'gdpr_art_6_1_c']); 1842 1843 $cat1 = api::create_category((object)['name' => 'a']); 1844 $cat2 = api::create_category((object)['name' => 'b']); 1845 $cat3 = api::create_category((object)['name' => 'c']); 1846 1847 $course1 = $this->getDataGenerator()->create_course(); 1848 $course2 = $this->getDataGenerator()->create_course(); 1849 1850 $module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1)); 1851 $module2 = $this->getDataGenerator()->create_module('resource', array('course' => $course2)); 1852 1853 return [ 1854 [$purpose1, $purpose2, $purpose3], 1855 [$cat1, $cat2, $cat3], 1856 [$course1, $course2], 1857 [$module1, $module2] 1858 ]; 1859 } 1860 1861 /** 1862 * Test that delete requests do not filter out protected purpose contexts if the the site is properly configured. 1863 */ 1864 public function test_get_approved_contextlist_collection_for_collection_delete_course_no_site_config() { 1865 $this->resetAfterTest(); 1866 1867 $user = $this->getDataGenerator()->create_user(); 1868 1869 $course = $this->getDataGenerator()->create_course(['startdate' => time() - YEARSECS, 'enddate' => time() - YEARSECS]); 1870 $coursecontext = \context_course::instance($course->id); 1871 1872 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); 1873 list(, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum'); 1874 $contextforum = \context_module::instance($forumcm->id); 1875 1876 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 1877 1878 // Create the initial contextlist. 1879 $initialcollection = new \core_privacy\local\request\contextlist_collection($user->id); 1880 1881 $contextlist = new \core_privacy\local\request\contextlist(); 1882 $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $coursecontext->id]); 1883 $contextlist->set_component('tool_dataprivacy'); 1884 $initialcollection->add_contextlist($contextlist); 1885 1886 $contextlist = new \core_privacy\local\request\contextlist(); 1887 $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $contextforum->id]); 1888 $contextlist->set_component('mod_forum'); 1889 $initialcollection->add_contextlist($contextlist); 1890 1891 $collection = api::get_approved_contextlist_collection_for_collection( 1892 $initialcollection, $user, api::DATAREQUEST_TYPE_DELETE); 1893 1894 $this->assertCount(2, $collection); 1895 1896 $list = $collection->get_contextlist_for_component('tool_dataprivacy'); 1897 $this->assertCount(1, $list); 1898 1899 $list = $collection->get_contextlist_for_component('mod_forum'); 1900 $this->assertCount(1, $list); 1901 } 1902 1903 /** 1904 * Test that delete requests do not filter out protected purpose contexts if they are already expired. 1905 */ 1906 public function test_get_approved_contextlist_collection_for_collection_delete_course_expired_protected() { 1907 $this->resetAfterTest(); 1908 1909 $purposes = $this->setup_basics('PT1H', 'PT1H', 'PT1H'); 1910 $purposes->course->purpose->set('protected', 1)->save(); 1911 1912 $user = $this->getDataGenerator()->create_user(); 1913 $course = $this->getDataGenerator()->create_course(['startdate' => time() - YEARSECS, 'enddate' => time() - YEARSECS]); 1914 $coursecontext = \context_course::instance($course->id); 1915 1916 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 1917 1918 // Create the initial contextlist. 1919 $contextlist = new \core_privacy\local\request\contextlist(); 1920 $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $coursecontext->id]); 1921 $contextlist->set_component('tool_dataprivacy'); 1922 1923 $initialcollection = new \core_privacy\local\request\contextlist_collection($user->id); 1924 $initialcollection->add_contextlist($contextlist); 1925 1926 $purposes->course->purpose->set('protected', 1)->save(); 1927 $collection = api::get_approved_contextlist_collection_for_collection( 1928 $initialcollection, $user, api::DATAREQUEST_TYPE_DELETE); 1929 1930 $this->assertCount(1, $collection); 1931 1932 $list = $collection->get_contextlist_for_component('tool_dataprivacy'); 1933 $this->assertCount(1, $list); 1934 } 1935 1936 /** 1937 * Test that delete requests does filter out protected purpose contexts which are not expired. 1938 */ 1939 public function test_get_approved_contextlist_collection_for_collection_delete_course_unexpired_protected() { 1940 $this->resetAfterTest(); 1941 1942 $purposes = $this->setup_basics('PT1H', 'PT1H', 'P1Y'); 1943 $purposes->course->purpose->set('protected', 1)->save(); 1944 1945 $user = $this->getDataGenerator()->create_user(); 1946 $course = $this->getDataGenerator()->create_course(['startdate' => time() - YEARSECS, 'enddate' => time()]); 1947 $coursecontext = \context_course::instance($course->id); 1948 1949 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 1950 1951 // Create the initial contextlist. 1952 $contextlist = new \core_privacy\local\request\contextlist(); 1953 $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $coursecontext->id]); 1954 $contextlist->set_component('tool_dataprivacy'); 1955 1956 $initialcollection = new \core_privacy\local\request\contextlist_collection($user->id); 1957 $initialcollection->add_contextlist($contextlist); 1958 1959 $purposes->course->purpose->set('protected', 1)->save(); 1960 $collection = api::get_approved_contextlist_collection_for_collection( 1961 $initialcollection, $user, api::DATAREQUEST_TYPE_DELETE); 1962 1963 $this->assertCount(0, $collection); 1964 1965 $list = $collection->get_contextlist_for_component('tool_dataprivacy'); 1966 $this->assertEmpty($list); 1967 } 1968 1969 /** 1970 * Test that delete requests do not filter out unexpired contexts if they are not protected. 1971 */ 1972 public function test_get_approved_contextlist_collection_for_collection_delete_course_unexpired_unprotected() { 1973 $this->resetAfterTest(); 1974 1975 $purposes = $this->setup_basics('PT1H', 'PT1H', 'P1Y'); 1976 $purposes->course->purpose->set('protected', 1)->save(); 1977 1978 $user = $this->getDataGenerator()->create_user(); 1979 $course = $this->getDataGenerator()->create_course(['startdate' => time() - YEARSECS, 'enddate' => time()]); 1980 $coursecontext = \context_course::instance($course->id); 1981 1982 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 1983 1984 // Create the initial contextlist. 1985 $contextlist = new \core_privacy\local\request\contextlist(); 1986 $contextlist->add_from_sql('SELECT id FROM {context} WHERE id = :contextid', ['contextid' => $coursecontext->id]); 1987 $contextlist->set_component('tool_dataprivacy'); 1988 1989 $initialcollection = new \core_privacy\local\request\contextlist_collection($user->id); 1990 $initialcollection->add_contextlist($contextlist); 1991 1992 $purposes->course->purpose->set('protected', 0)->save(); 1993 $collection = api::get_approved_contextlist_collection_for_collection( 1994 $initialcollection, $user, api::DATAREQUEST_TYPE_DELETE); 1995 1996 $this->assertCount(1, $collection); 1997 1998 $list = $collection->get_contextlist_for_component('tool_dataprivacy'); 1999 $this->assertCount(1, $list); 2000 } 2001 2002 /** 2003 * Data provider for \tool_dataprivacy_api_testcase::test_set_context_defaults 2004 */ 2005 public function set_context_defaults_provider() { 2006 $contextlevels = [ 2007 [CONTEXT_COURSECAT], 2008 [CONTEXT_COURSE], 2009 [CONTEXT_MODULE], 2010 [CONTEXT_BLOCK], 2011 ]; 2012 $paramsets = [ 2013 [true, true, false, false], // Inherit category and purpose, Not for activity, Don't override. 2014 [true, false, false, false], // Inherit category but not purpose, Not for activity, Don't override. 2015 [false, true, false, false], // Inherit purpose but not category, Not for activity, Don't override. 2016 [false, false, false, false], // Don't inherit both category and purpose, Not for activity, Don't override. 2017 [false, false, false, true], // Don't inherit both category and purpose, Not for activity, Override instances. 2018 ]; 2019 $data = []; 2020 foreach ($contextlevels as $level) { 2021 foreach ($paramsets as $set) { 2022 $data[] = array_merge($level, $set); 2023 } 2024 if ($level == CONTEXT_MODULE) { 2025 // Add a combination where defaults for activity is being set. 2026 $data[] = [CONTEXT_MODULE, false, false, true, false]; 2027 $data[] = [CONTEXT_MODULE, false, false, true, true]; 2028 } 2029 } 2030 return $data; 2031 } 2032 2033 /** 2034 * Test for \tool_dataprivacy\api::set_context_defaults() 2035 * 2036 * @dataProvider set_context_defaults_provider 2037 * @param int $contextlevel The context level 2038 * @param bool $inheritcategory Whether to set category value as INHERIT. 2039 * @param bool $inheritpurpose Whether to set purpose value as INHERIT. 2040 * @param bool $foractivity Whether to set defaults for an activity. 2041 * @param bool $override Whether to override instances. 2042 */ 2043 public function test_set_context_defaults($contextlevel, $inheritcategory, $inheritpurpose, $foractivity, $override) { 2044 $this->resetAfterTest(); 2045 2046 $generator = $this->getDataGenerator(); 2047 2048 // Generate course cat, course, block, assignment, forum instances. 2049 $coursecat = $generator->create_category(); 2050 $course = $generator->create_course(['category' => $coursecat->id]); 2051 $block = $generator->create_block('online_users'); 2052 $assign = $generator->create_module('assign', ['course' => $course->id]); 2053 $forum = $generator->create_module('forum', ['course' => $course->id]); 2054 2055 $coursecatcontext = \context_coursecat::instance($coursecat->id); 2056 $coursecontext = \context_course::instance($course->id); 2057 $blockcontext = \context_block::instance($block->id); 2058 2059 list($course, $assigncm) = get_course_and_cm_from_instance($assign->id, 'assign'); 2060 list($course, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum'); 2061 $assigncontext = \context_module::instance($assigncm->id); 2062 $forumcontext = \context_module::instance($forumcm->id); 2063 2064 // Generate purposes and categories. 2065 $category1 = api::create_category((object)['name' => 'Test category 1']); 2066 $category2 = api::create_category((object)['name' => 'Test category 2']); 2067 $purpose1 = api::create_purpose((object)[ 2068 'name' => 'Test purpose 1', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' 2069 ]); 2070 $purpose2 = api::create_purpose((object)[ 2071 'name' => 'Test purpose 2', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' 2072 ]); 2073 2074 // Assign purposes and categories to contexts. 2075 $coursecatctxinstance = api::set_context_instance((object) [ 2076 'contextid' => $coursecatcontext->id, 2077 'purposeid' => $purpose1->get('id'), 2078 'categoryid' => $category1->get('id'), 2079 ]); 2080 $coursectxinstance = api::set_context_instance((object) [ 2081 'contextid' => $coursecontext->id, 2082 'purposeid' => $purpose1->get('id'), 2083 'categoryid' => $category1->get('id'), 2084 ]); 2085 $blockctxinstance = api::set_context_instance((object) [ 2086 'contextid' => $blockcontext->id, 2087 'purposeid' => $purpose1->get('id'), 2088 'categoryid' => $category1->get('id'), 2089 ]); 2090 $assignctxinstance = api::set_context_instance((object) [ 2091 'contextid' => $assigncontext->id, 2092 'purposeid' => $purpose1->get('id'), 2093 'categoryid' => $category1->get('id'), 2094 ]); 2095 $forumctxinstance = api::set_context_instance((object) [ 2096 'contextid' => $forumcontext->id, 2097 'purposeid' => $purpose1->get('id'), 2098 'categoryid' => $category1->get('id'), 2099 ]); 2100 2101 $categoryid = $inheritcategory ? context_instance::INHERIT : $category2->get('id'); 2102 $purposeid = $inheritpurpose ? context_instance::INHERIT : $purpose2->get('id'); 2103 $activity = ''; 2104 if ($contextlevel == CONTEXT_MODULE && $foractivity) { 2105 $activity = 'assign'; 2106 } 2107 $result = api::set_context_defaults($contextlevel, $categoryid, $purposeid, $activity, $override); 2108 $this->assertTrue($result); 2109 2110 $targetctxinstance = false; 2111 switch ($contextlevel) { 2112 case CONTEXT_COURSECAT: 2113 $targetctxinstance = $coursecatctxinstance; 2114 break; 2115 case CONTEXT_COURSE: 2116 $targetctxinstance = $coursectxinstance; 2117 break; 2118 case CONTEXT_MODULE: 2119 $targetctxinstance = $assignctxinstance; 2120 break; 2121 case CONTEXT_BLOCK: 2122 $targetctxinstance = $blockctxinstance; 2123 break; 2124 } 2125 $this->assertNotFalse($targetctxinstance); 2126 2127 // Check the context instances. 2128 $instanceexists = context_instance::record_exists($targetctxinstance->get('id')); 2129 if ($override) { 2130 // If overridden, context instances on this context level would have been deleted. 2131 $this->assertFalse($instanceexists); 2132 2133 // Check forum context instance. 2134 $forumctxexists = context_instance::record_exists($forumctxinstance->get('id')); 2135 if ($contextlevel != CONTEXT_MODULE || $foractivity) { 2136 // The forum context instance won't be affected in this test if: 2137 // - The overridden defaults are not for context modules. 2138 // - Only the defaults for assign have been set. 2139 $this->assertTrue($forumctxexists); 2140 } else { 2141 // If we're overriding for the whole course module context level, 2142 // then this forum context instance will be deleted as well. 2143 $this->assertFalse($forumctxexists); 2144 } 2145 } else { 2146 // Otherwise, the context instance record remains. 2147 $this->assertTrue($instanceexists); 2148 } 2149 2150 // Check defaults. 2151 list($defaultpurpose, $defaultcategory) = data_registry::get_defaults($contextlevel, $activity); 2152 if (!$inheritpurpose) { 2153 $this->assertEquals($purposeid, $defaultpurpose); 2154 } 2155 if (!$inheritcategory) { 2156 $this->assertEquals($categoryid, $defaultcategory); 2157 } 2158 } 2159 2160 /** 2161 * Setup the basics with the specified retention period. 2162 * 2163 * @param string $system Retention policy for the system. 2164 * @param string $user Retention policy for users. 2165 * @param string $course Retention policy for courses. 2166 * @param string $activity Retention policy for activities. 2167 */ 2168 protected function setup_basics(string $system, string $user, string $course = null, string $activity = null) : \stdClass { 2169 $this->resetAfterTest(); 2170 2171 $purposes = (object) [ 2172 'system' => $this->create_and_set_purpose_for_contextlevel($system, CONTEXT_SYSTEM), 2173 'user' => $this->create_and_set_purpose_for_contextlevel($user, CONTEXT_USER), 2174 ]; 2175 2176 if (null !== $course) { 2177 $purposes->course = $this->create_and_set_purpose_for_contextlevel($course, CONTEXT_COURSE); 2178 } 2179 2180 if (null !== $activity) { 2181 $purposes->activity = $this->create_and_set_purpose_for_contextlevel($activity, CONTEXT_MODULE); 2182 } 2183 2184 return $purposes; 2185 } 2186 2187 /** 2188 * Create a retention period and set it for the specified context level. 2189 * 2190 * @param string $retention 2191 * @param int $contextlevel 2192 */ 2193 protected function create_and_set_purpose_for_contextlevel(string $retention, int $contextlevel) { 2194 $purpose = new purpose(0, (object) [ 2195 'name' => 'Test purpose ' . rand(1, 1000), 2196 'retentionperiod' => $retention, 2197 'lawfulbases' => 'gdpr_art_6_1_a', 2198 ]); 2199 $purpose->create(); 2200 2201 $cat = new category(0, (object) ['name' => 'Test category']); 2202 $cat->create(); 2203 2204 if ($contextlevel <= CONTEXT_USER) { 2205 $record = (object) [ 2206 'purposeid' => $purpose->get('id'), 2207 'categoryid' => $cat->get('id'), 2208 'contextlevel' => $contextlevel, 2209 ]; 2210 api::set_contextlevel($record); 2211 } else { 2212 list($purposevar, ) = data_registry::var_names_from_context( 2213 \context_helper::get_class_for_level(CONTEXT_COURSE) 2214 ); 2215 set_config($purposevar, $purpose->get('id'), 'tool_dataprivacy'); 2216 } 2217 2218 return (object) [ 2219 'purpose' => $purpose, 2220 'category' => $cat, 2221 ]; 2222 } 2223 2224 /** 2225 * Ensure that the find_ongoing_request_types_for_users only returns requests which are active. 2226 */ 2227 public function test_find_ongoing_request_types_for_users() { 2228 $this->resetAfterTest(); 2229 2230 // Create users and their requests:. 2231 // - u1 has no requests of any type. 2232 // - u2 has one rejected export request. 2233 // - u3 has one rejected other request. 2234 // - u4 has one rejected delete request. 2235 // - u5 has one active and one rejected export request. 2236 // - u6 has one active and one rejected other request. 2237 // - u7 has one active and one rejected delete request. 2238 // - u8 has one active export, and one active delete request. 2239 $u1 = $this->getDataGenerator()->create_user(); 2240 $u1expect = (object) []; 2241 2242 $u2 = $this->getDataGenerator()->create_user(); 2243 $this->create_request_with_type_and_status($u2->id, api::DATAREQUEST_TYPE_EXPORT, api::DATAREQUEST_STATUS_REJECTED); 2244 $u2expect = (object) []; 2245 2246 $u3 = $this->getDataGenerator()->create_user(); 2247 $this->create_request_with_type_and_status($u3->id, api::DATAREQUEST_TYPE_OTHERS, api::DATAREQUEST_STATUS_REJECTED); 2248 $u3expect = (object) []; 2249 2250 $u4 = $this->getDataGenerator()->create_user(); 2251 $this->create_request_with_type_and_status($u4->id, api::DATAREQUEST_TYPE_DELETE, api::DATAREQUEST_STATUS_REJECTED); 2252 $u4expect = (object) []; 2253 2254 $u5 = $this->getDataGenerator()->create_user(); 2255 $this->create_request_with_type_and_status($u5->id, api::DATAREQUEST_TYPE_EXPORT, api::DATAREQUEST_STATUS_REJECTED); 2256 $this->create_request_with_type_and_status($u5->id, api::DATAREQUEST_TYPE_EXPORT, api::DATAREQUEST_STATUS_APPROVED); 2257 $u5expect = (object) [ 2258 api::DATAREQUEST_TYPE_EXPORT => true, 2259 ]; 2260 2261 $u6 = $this->getDataGenerator()->create_user(); 2262 $this->create_request_with_type_and_status($u6->id, api::DATAREQUEST_TYPE_OTHERS, api::DATAREQUEST_STATUS_REJECTED); 2263 $this->create_request_with_type_and_status($u6->id, api::DATAREQUEST_TYPE_OTHERS, api::DATAREQUEST_STATUS_APPROVED); 2264 $u6expect = (object) [ 2265 api::DATAREQUEST_TYPE_OTHERS => true, 2266 ]; 2267 2268 $u7 = $this->getDataGenerator()->create_user(); 2269 $this->create_request_with_type_and_status($u7->id, api::DATAREQUEST_TYPE_DELETE, api::DATAREQUEST_STATUS_REJECTED); 2270 $this->create_request_with_type_and_status($u7->id, api::DATAREQUEST_TYPE_DELETE, api::DATAREQUEST_STATUS_APPROVED); 2271 $u7expect = (object) [ 2272 api::DATAREQUEST_TYPE_DELETE => true, 2273 ]; 2274 2275 $u8 = $this->getDataGenerator()->create_user(); 2276 $this->create_request_with_type_and_status($u8->id, api::DATAREQUEST_TYPE_EXPORT, api::DATAREQUEST_STATUS_APPROVED); 2277 $this->create_request_with_type_and_status($u8->id, api::DATAREQUEST_TYPE_DELETE, api::DATAREQUEST_STATUS_APPROVED); 2278 $u8expect = (object) [ 2279 api::DATAREQUEST_TYPE_EXPORT => true, 2280 api::DATAREQUEST_TYPE_DELETE => true, 2281 ]; 2282 2283 // Test with no users specified. 2284 $result = api::find_ongoing_request_types_for_users([]); 2285 $this->assertEquals([], $result); 2286 2287 // Fetch a subset of the users. 2288 $result = api::find_ongoing_request_types_for_users([$u3->id, $u4->id, $u5->id]); 2289 $this->assertEquals([ 2290 $u3->id => $u3expect, 2291 $u4->id => $u4expect, 2292 $u5->id => $u5expect, 2293 ], $result); 2294 2295 // Fetch the empty user. 2296 $result = api::find_ongoing_request_types_for_users([$u1->id]); 2297 $this->assertEquals([ 2298 $u1->id => $u1expect, 2299 ], $result); 2300 2301 // Fetch all. 2302 $result = api::find_ongoing_request_types_for_users( 2303 [$u1->id, $u2->id, $u3->id, $u4->id, $u5->id, $u6->id, $u7->id, $u8->id]); 2304 $this->assertEquals([ 2305 $u1->id => $u1expect, 2306 $u2->id => $u2expect, 2307 $u3->id => $u3expect, 2308 $u4->id => $u4expect, 2309 $u5->id => $u5expect, 2310 $u6->id => $u6expect, 2311 $u7->id => $u7expect, 2312 $u8->id => $u8expect, 2313 ], $result); 2314 } 2315 2316 /** 2317 * Create a new data request for the user with the type and status specified. 2318 * 2319 * @param int $userid 2320 * @param int $type 2321 * @param int $status 2322 * @return \tool_dataprivacy\data_request 2323 */ 2324 protected function create_request_with_type_and_status(int $userid, int $type, int $status) : \tool_dataprivacy\data_request { 2325 $request = new \tool_dataprivacy\data_request(0, (object) [ 2326 'userid' => $userid, 2327 'type' => $type, 2328 'status' => $status, 2329 ]); 2330 2331 $request->save(); 2332 2333 return $request; 2334 } 2335 2336 /** 2337 * Test whether user can create data download request for themselves 2338 */ 2339 public function test_can_create_data_download_request_for_self(): void { 2340 global $DB; 2341 2342 $this->resetAfterTest(); 2343 2344 $user = $this->getDataGenerator()->create_user(); 2345 $this->setUser($user); 2346 2347 // The default user role allows for the creation of download data requests. 2348 $this->assertTrue(api::can_create_data_download_request_for_self()); 2349 2350 // Prohibit that capability. 2351 $userrole = $DB->get_field('role', 'id', ['shortname' => 'user'], MUST_EXIST); 2352 assign_capability('tool/dataprivacy:downloadownrequest', CAP_PROHIBIT, $userrole, \context_user::instance($user->id)); 2353 2354 $this->assertFalse(api::can_create_data_download_request_for_self()); 2355 } 2356 2357 /** 2358 * Test user cannot create data deletion request for themselves if they don't have 2359 * "tool/dataprivacy:requestdelete" capability. 2360 * 2361 * @throws coding_exception 2362 */ 2363 public function test_can_create_data_deletion_request_for_self_no() { 2364 $this->resetAfterTest(); 2365 $userid = $this->getDataGenerator()->create_user()->id; 2366 $roleid = $this->getDataGenerator()->create_role(); 2367 assign_capability('tool/dataprivacy:requestdelete', CAP_PROHIBIT, $roleid, \context_user::instance($userid)); 2368 role_assign($roleid, $userid, \context_user::instance($userid)); 2369 $this->setUser($userid); 2370 $this->assertFalse(api::can_create_data_deletion_request_for_self()); 2371 } 2372 2373 /** 2374 * Test primary admin cannot create data deletion request for themselves 2375 */ 2376 public function test_can_create_data_deletion_request_for_self_primary_admin() { 2377 $this->resetAfterTest(); 2378 $this->setAdminUser(); 2379 $this->assertFalse(api::can_create_data_deletion_request_for_self()); 2380 } 2381 2382 /** 2383 * Test secondary admin can create data deletion request for themselves 2384 */ 2385 public function test_can_create_data_deletion_request_for_self_secondary_admin() { 2386 $this->resetAfterTest(); 2387 2388 $admin1 = $this->getDataGenerator()->create_user(); 2389 $admin2 = $this->getDataGenerator()->create_user(); 2390 2391 // The primary admin is the one listed first in the 'siteadmins' config. 2392 set_config('siteadmins', implode(',', [$admin1->id, $admin2->id])); 2393 2394 // Set the current user as the second admin (non-primary). 2395 $this->setUser($admin2); 2396 2397 $this->assertTrue(api::can_create_data_deletion_request_for_self()); 2398 } 2399 2400 /** 2401 * Test user can create data deletion request for themselves if they have 2402 * "tool/dataprivacy:requestdelete" capability. 2403 * 2404 * @throws coding_exception 2405 */ 2406 public function test_can_create_data_deletion_request_for_self_yes() { 2407 $this->resetAfterTest(); 2408 $userid = $this->getDataGenerator()->create_user()->id; 2409 $this->setUser($userid); 2410 $this->assertTrue(api::can_create_data_deletion_request_for_self()); 2411 } 2412 2413 /** 2414 * Test user cannot create data deletion request for another user if they 2415 * don't have "tool/dataprivacy:requestdeleteforotheruser" capability. 2416 * 2417 * @throws coding_exception 2418 * @throws dml_exception 2419 */ 2420 public function test_can_create_data_deletion_request_for_other_no() { 2421 $this->resetAfterTest(); 2422 $userid = $this->getDataGenerator()->create_user()->id; 2423 $this->setUser($userid); 2424 $this->assertFalse(api::can_create_data_deletion_request_for_other()); 2425 } 2426 2427 /** 2428 * Test user can create data deletion request for another user if they 2429 * don't have "tool/dataprivacy:requestdeleteforotheruser" capability. 2430 * 2431 * @throws coding_exception 2432 */ 2433 public function test_can_create_data_deletion_request_for_other_yes() { 2434 $this->resetAfterTest(); 2435 $userid = $this->getDataGenerator()->create_user()->id; 2436 $roleid = $this->getDataGenerator()->create_role(); 2437 $contextsystem = \context_system::instance(); 2438 assign_capability('tool/dataprivacy:requestdeleteforotheruser', CAP_ALLOW, $roleid, $contextsystem); 2439 role_assign($roleid, $userid, $contextsystem); 2440 $this->setUser($userid); 2441 $this->assertTrue(api::can_create_data_deletion_request_for_other($userid)); 2442 } 2443 2444 /** 2445 * Check parents can create data deletion request for their children (unless the child is the primary admin), 2446 * but not other users. 2447 * 2448 * @throws coding_exception 2449 * @throws dml_exception 2450 */ 2451 public function test_can_create_data_deletion_request_for_children() { 2452 $this->resetAfterTest(); 2453 2454 $parent = $this->getDataGenerator()->create_user(); 2455 $child = $this->getDataGenerator()->create_user(); 2456 $otheruser = $this->getDataGenerator()->create_user(); 2457 2458 $contextsystem = \context_system::instance(); 2459 $parentrole = $this->getDataGenerator()->create_role(); 2460 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, 2461 $parentrole, $contextsystem); 2462 assign_capability('tool/dataprivacy:makedatadeletionrequestsforchildren', CAP_ALLOW, 2463 $parentrole, $contextsystem); 2464 role_assign($parentrole, $parent->id, \context_user::instance($child->id)); 2465 2466 $this->setUser($parent); 2467 $this->assertTrue(api::can_create_data_deletion_request_for_children($child->id)); 2468 $this->assertFalse(api::can_create_data_deletion_request_for_children($otheruser->id)); 2469 2470 // Now make child the primary admin, confirm parent can't make deletion request. 2471 set_config('siteadmins', $child->id); 2472 $this->assertFalse(api::can_create_data_deletion_request_for_children($child->id)); 2473 } 2474 2475 /** 2476 * Data provider function for testing \tool_dataprivacy\api::queue_data_request_task(). 2477 * 2478 * @return array 2479 */ 2480 public function queue_data_request_task_provider() { 2481 return [ 2482 'With user ID provided' => [true], 2483 'Without user ID provided' => [false], 2484 ]; 2485 } 2486 2487 /** 2488 * Test for \tool_dataprivacy\api::queue_data_request_task(). 2489 * 2490 * @dataProvider queue_data_request_task_provider 2491 * @param bool $withuserid 2492 */ 2493 public function test_queue_data_request_task(bool $withuserid) { 2494 $this->resetAfterTest(); 2495 2496 $this->setAdminUser(); 2497 2498 if ($withuserid) { 2499 $user = $this->getDataGenerator()->create_user(); 2500 api::queue_data_request_task(1, $user->id); 2501 $expecteduserid = $user->id; 2502 } else { 2503 api::queue_data_request_task(1); 2504 $expecteduserid = null; 2505 } 2506 2507 // Test number of queued data request tasks. 2508 $datarequesttasks = manager::get_adhoc_tasks(process_data_request_task::class); 2509 $this->assertCount(1, $datarequesttasks); 2510 $requesttask = reset($datarequesttasks); 2511 $this->assertEquals($expecteduserid, $requesttask->get_userid()); 2512 } 2513 2514 /** 2515 * Data provider for test_is_automatic_request_approval_on(). 2516 */ 2517 public function automatic_request_approval_setting_provider() { 2518 return [ 2519 'Data export, not set' => [ 2520 'automaticdataexportapproval', api::DATAREQUEST_TYPE_EXPORT, null, false 2521 ], 2522 'Data export, turned on' => [ 2523 'automaticdataexportapproval', api::DATAREQUEST_TYPE_EXPORT, true, true 2524 ], 2525 'Data export, turned off' => [ 2526 'automaticdataexportapproval', api::DATAREQUEST_TYPE_EXPORT, false, false 2527 ], 2528 'Data deletion, not set' => [ 2529 'automaticdatadeletionapproval', api::DATAREQUEST_TYPE_DELETE, null, false 2530 ], 2531 'Data deletion, turned on' => [ 2532 'automaticdatadeletionapproval', api::DATAREQUEST_TYPE_DELETE, true, true 2533 ], 2534 'Data deletion, turned off' => [ 2535 'automaticdatadeletionapproval', api::DATAREQUEST_TYPE_DELETE, false, false 2536 ], 2537 ]; 2538 } 2539 2540 /** 2541 * Test for \tool_dataprivacy\api::is_automatic_request_approval_on(). 2542 * 2543 * @dataProvider automatic_request_approval_setting_provider 2544 * @param string $setting The automatic approval setting. 2545 * @param int $type The data request type. 2546 * @param bool $value The setting's value. 2547 * @param bool $expected The expected result. 2548 */ 2549 public function test_is_automatic_request_approval_on($setting, $type, $value, $expected) { 2550 $this->resetAfterTest(); 2551 2552 if ($value !== null) { 2553 set_config($setting, $value, 'tool_dataprivacy'); 2554 } 2555 2556 $this->assertEquals($expected, api::is_automatic_request_approval_on($type)); 2557 } 2558 2559 /** 2560 * Test approve part of context list before export if filtering of exports by course is allowed. 2561 */ 2562 public function test_approve_contexts_belonging_to_request(): void { 2563 global $DB; 2564 set_config('allowfiltering', 1, 'tool_dataprivacy'); 2565 $this->resetAfterTest(); 2566 $this->setAdminUser(); 2567 2568 $user = $this->getDataGenerator()->create_user(); 2569 2570 $course = $this->getDataGenerator()->create_course([]); 2571 $course2 = $this->getDataGenerator()->create_course([]); 2572 2573 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); 2574 $forum2 = $this->getDataGenerator()->create_module('forum', ['course' => $course2->id]); 2575 2576 $generator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 2577 2578 $record = new \stdClass(); 2579 $record->course = $course->id; 2580 $record->userid = $user->id; 2581 $record->forum = $forum->id; 2582 $generator->create_discussion($record); 2583 2584 $record->course = $course2->id; 2585 $record->forum = $forum2->id; 2586 $generator->create_discussion($record); 2587 2588 $coursecontext1 = \context_course::instance($course->id); 2589 $coursecontext2 = \context_course::instance($course2->id); 2590 2591 $forumcontext1 = \context_module::instance($forum->cmid); 2592 $forumcontext2 = \context_module::instance($forum2->cmid); 2593 2594 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 2595 $this->getDataGenerator()->enrol_user($user->id, $course2->id, 'student'); 2596 2597 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT); 2598 2599 ob_start(); 2600 $this->runAdhocTasks('tool_dataprivacy\task\initiate_data_request_task'); 2601 ob_end_clean(); 2602 2603 $contextcount = $DB->count_records('tool_dataprivacy_ctxlst_ctx'); 2604 api::approve_contexts_belonging_to_request($datarequest->get('id'), [$coursecontext1->id]); 2605 $items = $DB->get_records('tool_dataprivacy_ctxlst_ctx', null, '', 'id, contextid, status'); 2606 2607 $approvecontexts = []; 2608 $rejectedcontext = []; 2609 foreach ($items as $item) { 2610 if ($item->status == contextlist_context::STATUS_APPROVED) { 2611 $approvecontexts[] = $item->contextid; 2612 } 2613 if ($item->status == contextlist_context::STATUS_REJECTED) { 2614 $rejectedcontext[] = $item->contextid; 2615 } 2616 } 2617 2618 // Check no pending context left. 2619 $this->assertEquals($contextcount, count($approvecontexts) + count($rejectedcontext)); 2620 2621 $this->assertContains(strval($coursecontext1->id), $approvecontexts); 2622 $this->assertContains(strval($forumcontext1->id), $approvecontexts); 2623 $this->assertContains(strval($coursecontext2->id), $rejectedcontext); 2624 $this->assertContains(strval($forumcontext2->id), $rejectedcontext); 2625 } 2626 2627 /** 2628 * Test update request contexts with status. 2629 */ 2630 public function test_update_request_contexts_with_status(): void { 2631 global $DB; 2632 set_config('allowfiltering', 1, 'tool_dataprivacy'); 2633 $this->resetAfterTest(); 2634 $this->setAdminUser(); 2635 2636 $user = $this->getDataGenerator()->create_user(); 2637 2638 $course = $this->getDataGenerator()->create_course([]); 2639 2640 $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]); 2641 2642 $generator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 2643 2644 $record = new \stdClass(); 2645 $record->course = $course->id; 2646 $record->userid = $user->id; 2647 $record->forum = $forum->id; 2648 $generator->create_discussion($record); 2649 2650 $coursecontext = \context_course::instance($course->id); 2651 2652 $forumcontext = \context_module::instance($forum->cmid); 2653 2654 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 2655 2656 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT); 2657 2658 ob_start(); 2659 $this->runAdhocTasks('tool_dataprivacy\task\initiate_data_request_task'); 2660 ob_end_clean(); 2661 2662 $requestid = $datarequest->get("id"); 2663 2664 api::update_request_contexts_with_status($requestid, contextlist_context::STATUS_APPROVED); 2665 // Test all request contexts is updated with status approved. 2666 $results = $DB->get_records(contextlist_context::TABLE, ['contextid' => $coursecontext->id]); 2667 foreach ($results as $result) { 2668 $this->assertEquals($result->status, contextlist_context::STATUS_APPROVED); 2669 } 2670 $results = $DB->get_records(contextlist_context::TABLE, ['contextid' => $forumcontext->id]); 2671 foreach ($results as $result) { 2672 $this->assertEquals($result->status, contextlist_context::STATUS_APPROVED); 2673 } 2674 } 2675 2676 /** 2677 * Test api get_course_contexts_for_view_filter. 2678 */ 2679 public function test_get_course_contexts_for_view_filter(): void { 2680 set_config('allowfiltering', 1, 'tool_dataprivacy'); 2681 $this->resetAfterTest(); 2682 $this->setAdminUser(); 2683 2684 $user = $this->getDataGenerator()->create_user(); 2685 2686 $course = $this->getDataGenerator()->create_course([]); 2687 $course2 = $this->getDataGenerator()->create_course([]); 2688 2689 $record = new \stdClass(); 2690 $record->course = $course->id; 2691 $record->userid = $user->id; 2692 2693 $coursecontext1 = \context_course::instance($course->id); 2694 $coursecontext2 = \context_course::instance($course2->id); 2695 2696 $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student'); 2697 $this->getDataGenerator()->enrol_user($user->id, $course2->id, 'student'); 2698 2699 $datarequest = api::create_data_request($user->id, api::DATAREQUEST_TYPE_EXPORT); 2700 2701 ob_start(); 2702 $this->runAdhocTasks('tool_dataprivacy\task\initiate_data_request_task'); 2703 ob_end_clean(); 2704 2705 api::approve_contexts_belonging_to_request($datarequest->get('id'), [$coursecontext1->id]); 2706 $requestid = $datarequest->get('id'); 2707 2708 $result = api::get_course_contexts_for_view_filter($requestid); 2709 $this->assertContains($coursecontext1, $result); 2710 $this->assertContains($coursecontext2, $result); 2711 } 2712 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body