1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * External tests. 19 * 20 * @package tool_dataprivacy 21 * @copyright 2018 Jun Pataleta 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 global $CFG; 27 28 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 29 30 use tool_dataprivacy\api; 31 use tool_dataprivacy\context_instance; 32 use tool_dataprivacy\external; 33 34 /** 35 * External testcase. 36 * 37 * @package tool_dataprivacy 38 * @copyright 2018 Jun Pataleta 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 class tool_dataprivacy_external_testcase extends externallib_advanced_testcase { 42 43 /** 44 * Test for external::approve_data_request() with the user not logged in. 45 */ 46 public function test_approve_data_request_not_logged_in() { 47 $this->resetAfterTest(); 48 49 $generator = new testing_data_generator(); 50 $requester = $generator->create_user(); 51 $comment = 'sample comment'; 52 53 // Test data request creation. 54 $this->setUser($requester); 55 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 56 57 // Log out the user and set force login to true. 58 $this->setUser(); 59 60 $this->expectException(require_login_exception::class); 61 external::approve_data_request($datarequest->get('id')); 62 } 63 64 /** 65 * Test for external::approve_data_request() with the user not having a DPO role. 66 */ 67 public function test_approve_data_request_not_dpo() { 68 $this->resetAfterTest(); 69 70 $generator = new testing_data_generator(); 71 $requester = $generator->create_user(); 72 $comment = 'sample comment'; 73 74 // Test data request creation. 75 $this->setUser($requester); 76 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 77 78 // Login as the requester. 79 $this->setUser($requester); 80 $this->expectException(required_capability_exception::class); 81 external::approve_data_request($datarequest->get('id')); 82 } 83 84 /** 85 * Test for external::approve_data_request() for request that's not ready for approval 86 */ 87 public function test_approve_data_request_not_waiting_for_approval() { 88 $this->resetAfterTest(); 89 90 $generator = new testing_data_generator(); 91 $requester = $generator->create_user(); 92 $comment = 'sample comment'; 93 94 // Test data request creation. 95 $this->setUser($requester); 96 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 97 $datarequest->set('status', api::DATAREQUEST_STATUS_CANCELLED)->save(); 98 99 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 100 $this->setAdminUser(); 101 $this->expectException(moodle_exception::class); 102 external::approve_data_request($datarequest->get('id')); 103 } 104 105 /** 106 * Test for external::approve_data_request() 107 */ 108 public function test_approve_data_request() { 109 $this->resetAfterTest(); 110 111 $generator = new testing_data_generator(); 112 $requester = $generator->create_user(); 113 $comment = 'sample comment'; 114 115 // Test data request creation. 116 $this->setUser($requester); 117 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 118 119 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 120 $this->setAdminUser(); 121 api::update_request_status($datarequest->get('id'), api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 122 $result = external::approve_data_request($datarequest->get('id')); 123 $return = (object) external_api::clean_returnvalue(external::approve_data_request_returns(), $result); 124 $this->assertTrue($return->result); 125 $this->assertEmpty($return->warnings); 126 } 127 128 /** 129 * Test for external::approve_data_request() for a non-existent request ID. 130 */ 131 public function test_approve_data_request_non_existent() { 132 $this->resetAfterTest(); 133 134 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 135 $this->setAdminUser(); 136 137 $result = external::approve_data_request(1); 138 139 $return = (object) external_api::clean_returnvalue(external::approve_data_request_returns(), $result); 140 $this->assertFalse($return->result); 141 $this->assertCount(1, $return->warnings); 142 $warning = reset($return->warnings); 143 $this->assertEquals('errorrequestnotfound', $warning['warningcode']); 144 } 145 146 /** 147 * Test for external::cancel_data_request() of another user. 148 */ 149 public function test_cancel_data_request_other_user() { 150 $this->resetAfterTest(); 151 152 $generator = new testing_data_generator(); 153 $requester = $generator->create_user(); 154 $otheruser = $generator->create_user(); 155 $comment = 'sample comment'; 156 157 // Test data request creation. 158 $this->setUser($requester); 159 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 160 161 // Login as other user. 162 $this->setUser($otheruser); 163 164 $result = external::cancel_data_request($datarequest->get('id')); 165 $return = (object) external_api::clean_returnvalue(external::approve_data_request_returns(), $result); 166 $this->assertFalse($return->result); 167 $this->assertCount(1, $return->warnings); 168 $warning = reset($return->warnings); 169 $this->assertEquals('errorrequestnotfound', $warning['warningcode']); 170 } 171 172 /** 173 * Test cancellation of a request where you are the requester of another user's data. 174 */ 175 public function test_cancel_data_request_other_user_as_requester() { 176 $this->resetAfterTest(); 177 178 $generator = new testing_data_generator(); 179 $requester = $generator->create_user(); 180 $otheruser = $generator->create_user(); 181 $comment = 'sample comment'; 182 183 // Assign requester as otheruser'sparent. 184 $systemcontext = \context_system::instance(); 185 $parentrole = $generator->create_role(); 186 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 187 role_assign($parentrole, $requester->id, \context_user::instance($otheruser->id)); 188 189 // Test data request creation. 190 $this->setUser($requester); 191 $datarequest = api::create_data_request($otheruser->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 192 193 $result = external::cancel_data_request($datarequest->get('id')); 194 $return = (object) external_api::clean_returnvalue(external::approve_data_request_returns(), $result); 195 $this->assertTrue($return->result); 196 $this->assertEmpty($return->warnings); 197 } 198 199 /** 200 * Test cancellation of a request where you are the requester of another user's data. 201 */ 202 public function test_cancel_data_request_requester_lost_permissions() { 203 $this->resetAfterTest(); 204 205 $generator = new testing_data_generator(); 206 $requester = $generator->create_user(); 207 $otheruser = $generator->create_user(); 208 $comment = 'sample comment'; 209 210 // Assign requester as otheruser'sparent. 211 $systemcontext = \context_system::instance(); 212 $parentrole = $generator->create_role(); 213 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 214 role_assign($parentrole, $requester->id, \context_user::instance($otheruser->id)); 215 216 $this->setUser($requester); 217 $datarequest = api::create_data_request($otheruser->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 218 219 // Unassign the role. 220 role_unassign($parentrole, $requester->id, \context_user::instance($otheruser->id)->id); 221 222 // This user can no longer make the request. 223 $this->expectException(required_capability_exception::class); 224 225 $result = external::cancel_data_request($datarequest->get('id')); 226 } 227 228 /** 229 * Test cancellation of a request where you are the requester of another user's data. 230 */ 231 public function test_cancel_data_request_other_user_as_child() { 232 $this->resetAfterTest(); 233 234 $generator = new testing_data_generator(); 235 $requester = $generator->create_user(); 236 $otheruser = $generator->create_user(); 237 $comment = 'sample comment'; 238 239 // Assign requester as otheruser'sparent. 240 $systemcontext = \context_system::instance(); 241 $parentrole = $generator->create_role(); 242 assign_capability('tool/dataprivacy:makedatarequestsforchildren', CAP_ALLOW, $parentrole, $systemcontext); 243 role_assign($parentrole, $requester->id, \context_user::instance($otheruser->id)); 244 245 // Test data request creation. 246 $this->setUser($otheruser); 247 $datarequest = api::create_data_request($otheruser->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 248 249 $result = external::cancel_data_request($datarequest->get('id')); 250 $return = (object) external_api::clean_returnvalue(external::approve_data_request_returns(), $result); 251 $this->assertTrue($return->result); 252 $this->assertEmpty($return->warnings); 253 } 254 255 /** 256 * Test for external::cancel_data_request() 257 */ 258 public function test_cancel_data_request() { 259 $this->resetAfterTest(); 260 261 $generator = new testing_data_generator(); 262 $requester = $generator->create_user(); 263 $comment = 'sample comment'; 264 265 // Test data request creation. 266 $this->setUser($requester); 267 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 268 269 // Test cancellation. 270 $this->setUser($requester); 271 $result = external::cancel_data_request($datarequest->get('id')); 272 273 $return = (object) external_api::clean_returnvalue(external::approve_data_request_returns(), $result); 274 $this->assertTrue($return->result); 275 $this->assertEmpty($return->warnings); 276 } 277 278 /** 279 * Test contact DPO. 280 */ 281 public function test_contact_dpo() { 282 $this->resetAfterTest(); 283 284 $generator = new testing_data_generator(); 285 $user = $generator->create_user(); 286 287 $this->setUser($user); 288 $message = 'Hello world!'; 289 $result = external::contact_dpo($message); 290 $return = (object) external_api::clean_returnvalue(external::contact_dpo_returns(), $result); 291 $this->assertTrue($return->result); 292 $this->assertEmpty($return->warnings); 293 } 294 295 /** 296 * Test contact DPO with message containing invalid input. 297 */ 298 public function test_contact_dpo_with_nasty_input() { 299 $this->resetAfterTest(); 300 301 $generator = new testing_data_generator(); 302 $user = $generator->create_user(); 303 304 $this->setUser($user); 305 $this->expectException('invalid_parameter_exception'); 306 external::contact_dpo('de<>\\..scription'); 307 } 308 309 /** 310 * Test for external::deny_data_request() with the user not logged in. 311 */ 312 public function test_deny_data_request_not_logged_in() { 313 $this->resetAfterTest(); 314 315 $generator = new testing_data_generator(); 316 $requester = $generator->create_user(); 317 $comment = 'sample comment'; 318 319 // Test data request creation. 320 $this->setUser($requester); 321 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 322 323 // Log out. 324 $this->setUser(); 325 $this->expectException(require_login_exception::class); 326 external::deny_data_request($datarequest->get('id')); 327 } 328 329 /** 330 * Test for external::deny_data_request() with the user not having a DPO role. 331 */ 332 public function test_deny_data_request_not_dpo() { 333 $this->resetAfterTest(); 334 335 $generator = new testing_data_generator(); 336 $requester = $generator->create_user(); 337 $comment = 'sample comment'; 338 339 $this->setUser($requester); 340 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 341 342 // Login as the requester. 343 $this->setUser($requester); 344 $this->expectException(required_capability_exception::class); 345 external::deny_data_request($datarequest->get('id')); 346 } 347 348 /** 349 * Test for external::deny_data_request() for request that's not ready for approval 350 */ 351 public function test_deny_data_request_not_waiting_for_approval() { 352 $this->resetAfterTest(); 353 354 $generator = new testing_data_generator(); 355 $requester = $generator->create_user(); 356 $comment = 'sample comment'; 357 358 $this->setUser($requester); 359 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 360 $datarequest->set('status', api::DATAREQUEST_STATUS_CANCELLED)->save(); 361 362 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 363 $this->setAdminUser(); 364 $this->expectException(moodle_exception::class); 365 external::deny_data_request($datarequest->get('id')); 366 } 367 368 /** 369 * Test for external::deny_data_request() 370 */ 371 public function test_deny_data_request() { 372 $this->resetAfterTest(); 373 374 $generator = new testing_data_generator(); 375 $requester = $generator->create_user(); 376 $comment = 'sample comment'; 377 378 $this->setUser($requester); 379 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 380 381 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 382 $this->setAdminUser(); 383 api::update_request_status($datarequest->get('id'), api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 384 $result = external::approve_data_request($datarequest->get('id')); 385 $return = (object) external_api::clean_returnvalue(external::deny_data_request_returns(), $result); 386 $this->assertTrue($return->result); 387 $this->assertEmpty($return->warnings); 388 } 389 390 /** 391 * Test for external::deny_data_request() for a non-existent request ID. 392 */ 393 public function test_deny_data_request_non_existent() { 394 $this->resetAfterTest(); 395 396 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 397 $this->setAdminUser(); 398 $result = external::deny_data_request(1); 399 400 $return = (object) external_api::clean_returnvalue(external::deny_data_request_returns(), $result); 401 $this->assertFalse($return->result); 402 $this->assertCount(1, $return->warnings); 403 $warning = reset($return->warnings); 404 $this->assertEquals('errorrequestnotfound', $warning['warningcode']); 405 } 406 407 /** 408 * Test for external::get_data_request() with the user not logged in. 409 */ 410 public function test_get_data_request_not_logged_in() { 411 $this->resetAfterTest(); 412 413 $generator = new testing_data_generator(); 414 $requester = $generator->create_user(); 415 $comment = 'sample comment'; 416 417 $this->setUser($requester); 418 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 419 420 $this->setUser(); 421 $this->expectException(require_login_exception::class); 422 external::get_data_request($datarequest->get('id')); 423 } 424 425 /** 426 * Test for external::get_data_request() with the user not having a DPO role. 427 */ 428 public function test_get_data_request_not_dpo() { 429 $this->resetAfterTest(); 430 431 $generator = new testing_data_generator(); 432 $requester = $generator->create_user(); 433 $otheruser = $generator->create_user(); 434 $comment = 'sample comment'; 435 436 $this->setUser($requester); 437 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 438 439 // Login as the otheruser. 440 $this->setUser($otheruser); 441 $this->expectException(required_capability_exception::class); 442 external::get_data_request($datarequest->get('id')); 443 } 444 445 /** 446 * Test for external::get_data_request() 447 */ 448 public function test_get_data_request() { 449 $this->resetAfterTest(); 450 451 $generator = new testing_data_generator(); 452 $requester = $generator->create_user(); 453 $comment = 'sample comment'; 454 455 $this->setUser($requester); 456 $datarequest = api::create_data_request($requester->id, api::DATAREQUEST_TYPE_EXPORT, $comment); 457 458 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 459 $this->setAdminUser(); 460 $result = external::get_data_request($datarequest->get('id')); 461 462 $return = (object) external_api::clean_returnvalue(external::get_data_request_returns(), $result); 463 $this->assertEquals(api::DATAREQUEST_TYPE_EXPORT, $return->result['type']); 464 $this->assertEquals('sample comment', $return->result['comments']); 465 $this->assertEquals($requester->id, $return->result['userid']); 466 $this->assertEquals($requester->id, $return->result['requestedby']); 467 $this->assertEmpty($return->warnings); 468 } 469 470 /** 471 * Test for external::get_data_request() for a non-existent request ID. 472 */ 473 public function test_get_data_request_non_existent() { 474 $this->resetAfterTest(); 475 476 // Admin as DPO. (The default when no one's assigned as a DPO in the site). 477 $this->setAdminUser(); 478 $this->expectException(dml_missing_record_exception::class); 479 external::get_data_request(1); 480 } 481 482 /** 483 * Test for \tool_dataprivacy\external::set_context_defaults() 484 * when called by a user that doesn't have the manage registry capability. 485 */ 486 public function test_set_context_defaults_no_capability() { 487 $this->resetAfterTest(); 488 489 $generator = $this->getDataGenerator(); 490 $user = $generator->create_user(); 491 $this->setUser($user); 492 $this->expectException(required_capability_exception::class); 493 external::set_context_defaults(CONTEXT_COURSECAT, context_instance::INHERIT, context_instance::INHERIT, '', false); 494 } 495 496 /** 497 * Test for \tool_dataprivacy\external::set_context_defaults(). 498 * 499 * We're just checking the module context level here to test the WS function. 500 * More testing is done in \tool_dataprivacy_api_testcase::test_set_context_defaults(). 501 * 502 * @dataProvider get_options_provider 503 * @param bool $modulelevel Whether defaults are to be applied on the module context level or for an activity only. 504 * @param bool $override Whether to override instances. 505 */ 506 public function test_set_context_defaults($modulelevel, $override) { 507 $this->resetAfterTest(); 508 509 $this->setAdminUser(); 510 $generator = $this->getDataGenerator(); 511 512 // Generate course cat, course, block, assignment, forum instances. 513 $coursecat = $generator->create_category(); 514 $course = $generator->create_course(['category' => $coursecat->id]); 515 $assign = $generator->create_module('assign', ['course' => $course->id]); 516 list($course, $assigncm) = get_course_and_cm_from_instance($assign->id, 'assign'); 517 $assigncontext = context_module::instance($assigncm->id); 518 519 // Generate purpose and category. 520 $category1 = api::create_category((object)['name' => 'Test category 1']); 521 $category2 = api::create_category((object)['name' => 'Test category 2']); 522 $purpose1 = api::create_purpose((object)[ 523 'name' => 'Test purpose 1', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' 524 ]); 525 $purpose2 = api::create_purpose((object)[ 526 'name' => 'Test purpose 2', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' 527 ]); 528 529 // Set a custom purpose and ID for this assignment instance. 530 $assignctxinstance = api::set_context_instance((object) [ 531 'contextid' => $assigncontext->id, 532 'purposeid' => $purpose1->get('id'), 533 'categoryid' => $category1->get('id'), 534 ]); 535 536 $modulename = $modulelevel ? 'assign' : ''; 537 $categoryid = $category2->get('id'); 538 $purposeid = $purpose2->get('id'); 539 $result = external::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, $modulename, $override); 540 541 // Extract the result. 542 $return = external_api::clean_returnvalue(external::set_context_defaults_returns(), $result); 543 $this->assertTrue($return['result']); 544 545 // Check the assignment context instance. 546 $instanceexists = context_instance::record_exists($assignctxinstance->get('id')); 547 if ($override) { 548 // The custom assign instance should have been deleted. 549 $this->assertFalse($instanceexists); 550 } else { 551 // The custom assign instance should still exist. 552 $this->assertTrue($instanceexists); 553 } 554 555 // Check the saved defaults. 556 list($savedpurpose, $savedcategory) = \tool_dataprivacy\data_registry::get_defaults(CONTEXT_MODULE, $modulename); 557 $this->assertEquals($categoryid, $savedcategory); 558 $this->assertEquals($purposeid, $savedpurpose); 559 } 560 561 /** 562 * Test for \tool_dataprivacy\external::get_category_options() 563 * when called by a user that doesn't have the manage registry capability. 564 */ 565 public function test_get_category_options_no_capability() { 566 $this->resetAfterTest(); 567 568 $user = $this->getDataGenerator()->create_user(); 569 $this->setUser($user); 570 571 $this->expectException(required_capability_exception::class); 572 external::get_category_options(true, true); 573 } 574 575 /** 576 * Data provider for \tool_dataprivacy_external_testcase::test_XX_options(). 577 */ 578 public function get_options_provider() { 579 return [ 580 [false, false], 581 [false, true], 582 [true, false], 583 [true, true], 584 ]; 585 } 586 587 /** 588 * Test for \tool_dataprivacy\external::get_category_options(). 589 * 590 * @dataProvider get_options_provider 591 * @param bool $includeinherit Whether "Inherit" would be included to the options. 592 * @param bool $includenotset Whether "Not set" would be included to the options. 593 */ 594 public function test_get_category_options($includeinherit, $includenotset) { 595 $this->resetAfterTest(); 596 $this->setAdminUser(); 597 598 // Prepare our expected options. 599 $expectedoptions = []; 600 if ($includeinherit) { 601 $expectedoptions[] = [ 602 'id' => context_instance::INHERIT, 603 'name' => get_string('inherit', 'tool_dataprivacy'), 604 ]; 605 } 606 607 if ($includenotset) { 608 $expectedoptions[] = [ 609 'id' => context_instance::NOTSET, 610 'name' => get_string('notset', 'tool_dataprivacy'), 611 ]; 612 } 613 614 for ($i = 1; $i <= 3; $i++) { 615 $category = api::create_category((object)['name' => 'Category ' . $i]); 616 $expectedoptions[] = [ 617 'id' => $category->get('id'), 618 'name' => $category->get('name'), 619 ]; 620 } 621 622 // Call the WS function. 623 $result = external::get_category_options($includeinherit, $includenotset); 624 625 // Extract the options. 626 $return = (object) external_api::clean_returnvalue(external::get_category_options_returns(), $result); 627 $options = $return->options; 628 629 // Make sure everything checks out. 630 $this->assertCount(count($expectedoptions), $options); 631 foreach ($options as $option) { 632 $this->assertContains($option, $expectedoptions); 633 } 634 } 635 636 /** 637 * Test for \tool_dataprivacy\external::get_purpose_options() 638 * when called by a user that doesn't have the manage registry capability. 639 */ 640 public function test_get_purpose_options_no_capability() { 641 $this->resetAfterTest(); 642 $generator = $this->getDataGenerator(); 643 $user = $generator->create_user(); 644 $this->setUser($user); 645 $this->expectException(required_capability_exception::class); 646 external::get_category_options(true, true); 647 } 648 649 /** 650 * Test for \tool_dataprivacy\external::get_purpose_options(). 651 * 652 * @dataProvider get_options_provider 653 * @param bool $includeinherit Whether "Inherit" would be included to the options. 654 * @param bool $includenotset Whether "Not set" would be included to the options. 655 */ 656 public function test_get_purpose_options($includeinherit, $includenotset) { 657 $this->resetAfterTest(); 658 $this->setAdminUser(); 659 660 // Prepare our expected options. 661 $expectedoptions = []; 662 if ($includeinherit) { 663 $expectedoptions[] = [ 664 'id' => context_instance::INHERIT, 665 'name' => get_string('inherit', 'tool_dataprivacy'), 666 ]; 667 } 668 669 if ($includenotset) { 670 $expectedoptions[] = [ 671 'id' => context_instance::NOTSET, 672 'name' => get_string('notset', 'tool_dataprivacy'), 673 ]; 674 } 675 676 for ($i = 1; $i <= 3; $i++) { 677 $purpose = api::create_purpose((object)[ 678 'name' => 'Purpose ' . $i, 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' 679 ]); 680 $expectedoptions[] = [ 681 'id' => $purpose->get('id'), 682 'name' => $purpose->get('name'), 683 ]; 684 } 685 686 // Call the WS function. 687 $result = external::get_purpose_options($includeinherit, $includenotset); 688 689 // Extract the options. 690 $return = (object) external_api::clean_returnvalue(external::get_purpose_options_returns(), $result); 691 $options = $return->options; 692 693 // Make sure everything checks out. 694 $this->assertCount(count($expectedoptions), $options); 695 foreach ($options as $option) { 696 $this->assertContains($option, $expectedoptions); 697 } 698 } 699 700 /** 701 * Data provider for \tool_dataprivacy_external_testcase::get_activity_options(). 702 */ 703 public function get_activity_options_provider() { 704 return [ 705 [false, false, true], 706 [false, true, true], 707 [true, false, true], 708 [true, true, true], 709 [false, false, false], 710 [false, true, false], 711 [true, false, false], 712 [true, true, false], 713 ]; 714 } 715 716 /** 717 * Test for \tool_dataprivacy\external::get_activity_options(). 718 * 719 * @dataProvider get_activity_options_provider 720 * @param bool $inheritcategory Whether the category would be set to "Inherit". 721 * @param bool $inheritpurpose Whether the purpose would be set to "Inherit". 722 * @param bool $nodefaults Whether to fetch only activities that don't have defaults. 723 */ 724 public function test_get_activity_options($inheritcategory, $inheritpurpose, $nodefaults) { 725 $this->resetAfterTest(); 726 $this->setAdminUser(); 727 728 $category = api::create_category((object)['name' => 'Test category']); 729 $purpose = api::create_purpose((object)[ 730 'name' => 'Test purpose ', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' 731 ]); 732 $categoryid = $category->get('id'); 733 $purposeid = $purpose->get('id'); 734 735 if ($inheritcategory) { 736 $categoryid = context_instance::INHERIT; 737 } 738 if ($inheritpurpose) { 739 $purposeid = context_instance::INHERIT; 740 } 741 742 // Set the context default for the assignment module. 743 api::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, 'assign'); 744 745 // Call the WS function. 746 $result = external::get_activity_options($nodefaults); 747 748 // Extract the options. 749 $return = (object) external_api::clean_returnvalue(external::get_activity_options_returns(), $result); 750 $options = $return->options; 751 752 // Make sure the options list is not empty. 753 $this->assertNotEmpty($options); 754 755 $pluginwithdefaults = [ 756 'name' => 'assign', 757 'displayname' => get_string('pluginname', 'assign') 758 ]; 759 760 // If we don't want plugins with defaults to be listed or if both of the category and purpose are set to inherit, 761 // the assign module should be listed. 762 if (!$nodefaults || ($inheritcategory && $inheritpurpose)) { 763 $this->assertContains($pluginwithdefaults, $options); 764 } else { 765 $this->assertNotContains($pluginwithdefaults, $options); 766 } 767 } 768 769 /** 770 * Test for external::bulk_approve_data_requests(). 771 */ 772 public function test_bulk_approve_data_requests() { 773 $this->resetAfterTest(); 774 775 // Create delete data requests. 776 $requester1 = $this->getDataGenerator()->create_user(); 777 $this->setUser($requester1->id); 778 $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 779 $requestid1 = $datarequest1->get('id'); 780 781 $requester2 = $this->getDataGenerator()->create_user(); 782 $this->setUser($requester2->id); 783 $datarequest2 = api::create_data_request($requester2->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 784 $requestid2 = $datarequest2->get('id'); 785 786 // Approve the requests. 787 $this->setAdminUser(); 788 api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 789 api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 790 $result = external::bulk_approve_data_requests([$requestid1, $requestid2]); 791 792 $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result); 793 $this->assertTrue($return->result); 794 $this->assertEmpty($return->warnings); 795 } 796 797 /** 798 * Test for external::bulk_approve_data_requests() for a non-existent request ID. 799 */ 800 public function test_bulk_approve_data_requests_non_existent() { 801 $this->resetAfterTest(); 802 803 $this->setAdminUser(); 804 805 $result = external::bulk_approve_data_requests([42]); 806 807 $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result); 808 $this->assertFalse($return->result); 809 $this->assertCount(1, $return->warnings); 810 $warning = reset($return->warnings); 811 $this->assertEquals('errorrequestnotfound', $warning['warningcode']); 812 $this->assertEquals(42, $warning['item']); 813 } 814 815 /** 816 * Test for external::bulk_deny_data_requests() for a user without permission to deny requests. 817 */ 818 public function test_bulk_approve_data_requests_no_permission() { 819 $this->resetAfterTest(); 820 821 // Create delete data requests. 822 $requester1 = $this->getDataGenerator()->create_user(); 823 $this->setUser($requester1->id); 824 $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 825 $requestid1 = $datarequest1->get('id'); 826 827 $requester2 = $this->getDataGenerator()->create_user(); 828 $this->setUser($requester2->id); 829 $datarequest2 = api::create_data_request($requester2->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 830 $requestid2 = $datarequest2->get('id'); 831 832 $this->setAdminUser(); 833 api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 834 api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 835 836 // Approve the requests. 837 $uut = $this->getDataGenerator()->create_user(); 838 $this->setUser($uut); 839 840 $this->expectException(required_capability_exception::class); 841 $result = external::bulk_approve_data_requests([$requestid1, $requestid2]); 842 } 843 844 /** 845 * Test for external::bulk_deny_data_requests() for a user without permission to deny requests. 846 */ 847 public function test_bulk_approve_data_requests_own_request() { 848 $this->resetAfterTest(); 849 850 // Create delete data requests. 851 $requester1 = $this->getDataGenerator()->create_user(); 852 $this->setUser($requester1->id); 853 $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 854 $requestid1 = $datarequest1->get('id'); 855 856 $requester2 = $this->getDataGenerator()->create_user(); 857 $this->setUser($requester2->id); 858 $datarequest2 = api::create_data_request($requester2->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 859 $requestid2 = $datarequest2->get('id'); 860 861 $this->setAdminUser(); 862 api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 863 api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 864 865 // Deny the requests. 866 $this->setUser($requester1); 867 868 $this->expectException(required_capability_exception::class); 869 $result = external::bulk_approve_data_requests([$requestid1]); 870 } 871 872 /** 873 * Test for external::bulk_deny_data_requests(). 874 */ 875 public function test_bulk_deny_data_requests() { 876 $this->resetAfterTest(); 877 878 // Create delete data requests. 879 $requester1 = $this->getDataGenerator()->create_user(); 880 $this->setUser($requester1->id); 881 $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 882 $requestid1 = $datarequest1->get('id'); 883 884 $requester2 = $this->getDataGenerator()->create_user(); 885 $this->setUser($requester2->id); 886 $datarequest2 = api::create_data_request($requester2->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 887 $requestid2 = $datarequest2->get('id'); 888 889 // Deny the requests. 890 $this->setAdminUser(); 891 api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 892 api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 893 $result = external::bulk_deny_data_requests([$requestid1, $requestid2]); 894 895 $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result); 896 $this->assertTrue($return->result); 897 $this->assertEmpty($return->warnings); 898 } 899 900 /** 901 * Test for external::bulk_deny_data_requests() for a non-existent request ID. 902 */ 903 public function test_bulk_deny_data_requests_non_existent() { 904 $this->resetAfterTest(); 905 906 $this->setAdminUser(); 907 $result = external::bulk_deny_data_requests([42]); 908 $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result); 909 910 $this->assertFalse($return->result); 911 $this->assertCount(1, $return->warnings); 912 $warning = reset($return->warnings); 913 $this->assertEquals('errorrequestnotfound', $warning['warningcode']); 914 $this->assertEquals(42, $warning['item']); 915 } 916 917 /** 918 * Test for external::bulk_deny_data_requests() for a user without permission to deny requests. 919 */ 920 public function test_bulk_deny_data_requests_no_permission() { 921 $this->resetAfterTest(); 922 923 // Create delete data requests. 924 $requester1 = $this->getDataGenerator()->create_user(); 925 $this->setUser($requester1->id); 926 $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 927 $requestid1 = $datarequest1->get('id'); 928 929 $requester2 = $this->getDataGenerator()->create_user(); 930 $this->setUser($requester2->id); 931 $datarequest2 = api::create_data_request($requester2->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 932 $requestid2 = $datarequest2->get('id'); 933 934 $this->setAdminUser(); 935 api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 936 api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 937 938 // Deny the requests. 939 $uut = $this->getDataGenerator()->create_user(); 940 $this->setUser($uut); 941 942 $this->expectException(required_capability_exception::class); 943 $result = external::bulk_deny_data_requests([$requestid1, $requestid2]); 944 } 945 946 /** 947 * Test for external::bulk_deny_data_requests() for a user cannot approve their own request. 948 */ 949 public function test_bulk_deny_data_requests_own_request() { 950 $this->resetAfterTest(); 951 952 // Create delete data requests. 953 $requester1 = $this->getDataGenerator()->create_user(); 954 $this->setUser($requester1->id); 955 $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 956 $requestid1 = $datarequest1->get('id'); 957 958 $requester2 = $this->getDataGenerator()->create_user(); 959 $this->setUser($requester2->id); 960 $datarequest2 = api::create_data_request($requester2->id, api::DATAREQUEST_TYPE_DELETE, 'Example comment'); 961 $requestid2 = $datarequest2->get('id'); 962 963 $this->setAdminUser(); 964 api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 965 api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL); 966 967 // Deny the requests. 968 $this->setUser($requester1); 969 970 $this->expectException(required_capability_exception::class); 971 $result = external::bulk_deny_data_requests([$requestid1]); 972 } 973 974 /** 975 * Test for external::get_users(), case search using non-identity field without 976 * facing any permission problem. 977 * 978 * @throws coding_exception 979 * @throws dml_exception 980 * @throws invalid_parameter_exception 981 * @throws required_capability_exception 982 * @throws restricted_context_exception 983 */ 984 public function test_get_users_using_using_non_identity() { 985 $this->resetAfterTest(); 986 $context = context_system::instance(); 987 $requester = $this->getDataGenerator()->create_user(); 988 $role = $this->getDataGenerator()->create_role(); 989 role_assign($role, $requester->id, $context); 990 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $role, $context); 991 $this->setUser($requester); 992 993 $this->getDataGenerator()->create_user([ 994 'firstname' => 'First Student' 995 ]); 996 $student2 = $this->getDataGenerator()->create_user([ 997 'firstname' => 'Second Student' 998 ]); 999 1000 $results = external::get_users('Second'); 1001 $this->assertCount(1, $results); 1002 $this->assertEquals((object)[ 1003 'id' => $student2->id, 1004 'fullname' => fullname($student2), 1005 'extrafields' => [] 1006 ], $results[$student2->id]); 1007 } 1008 1009 /** 1010 * Test for external::get_users(), case search using identity field but 1011 * don't have "moodle/site:viewuseridentity" permission. 1012 * 1013 * @throws coding_exception 1014 * @throws dml_exception 1015 * @throws invalid_parameter_exception 1016 * @throws required_capability_exception 1017 * @throws restricted_context_exception 1018 */ 1019 public function test_get_users_using_identity_without_permission() { 1020 global $CFG; 1021 1022 $this->resetAfterTest(); 1023 $CFG->showuseridentity = 'institution'; 1024 1025 // Create requester user and assign correct capability. 1026 $context = context_system::instance(); 1027 $requester = $this->getDataGenerator()->create_user(); 1028 $role = $this->getDataGenerator()->create_role(); 1029 role_assign($role, $requester->id, $context); 1030 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $role, $context); 1031 $this->setUser($requester); 1032 1033 $this->getDataGenerator()->create_user([ 1034 'institution' => 'University1' 1035 ]); 1036 1037 $results = external::get_users('University1'); 1038 $this->assertEmpty($results); 1039 } 1040 1041 /** 1042 * Test for external::get_users(), case search using disabled identity field 1043 * even they have "moodle/site:viewuseridentity" permission. 1044 * 1045 * @throws coding_exception 1046 * @throws dml_exception 1047 * @throws invalid_parameter_exception 1048 * @throws required_capability_exception 1049 * @throws restricted_context_exception 1050 */ 1051 public function test_get_users_using_field_not_in_identity() { 1052 $this->resetAfterTest(); 1053 1054 $context = context_system::instance(); 1055 $requester = $this->getDataGenerator()->create_user(); 1056 $role = $this->getDataGenerator()->create_role(); 1057 role_assign($role, $requester->id, $context); 1058 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $role, $context); 1059 assign_capability('moodle/site:viewuseridentity', CAP_ALLOW, $role, $context); 1060 $this->setUser($requester); 1061 1062 $this->getDataGenerator()->create_user([ 1063 'institution' => 'University1' 1064 ]); 1065 1066 $results = external::get_users('University1'); 1067 $this->assertEmpty($results); 1068 } 1069 1070 /** 1071 * Test for external::get_users(), case search using enabled identity field 1072 * with "moodle/site:viewuseridentity" permission. 1073 * 1074 * @throws coding_exception 1075 * @throws dml_exception 1076 * @throws invalid_parameter_exception 1077 * @throws required_capability_exception 1078 * @throws restricted_context_exception 1079 */ 1080 public function test_get_users() { 1081 global $CFG; 1082 $this->resetAfterTest(); 1083 $CFG->showuseridentity = 'institution'; 1084 $context = context_system::instance(); 1085 $requester = $this->getDataGenerator()->create_user(); 1086 $role = $this->getDataGenerator()->create_role(); 1087 role_assign($role, $requester->id, $context); 1088 assign_capability('tool/dataprivacy:managedatarequests', CAP_ALLOW, $role, $context); 1089 assign_capability('moodle/site:viewuseridentity', CAP_ALLOW, $role, $context); 1090 $this->setUser($requester); 1091 1092 $student1 = $this->getDataGenerator()->create_user([ 1093 'institution' => 'University1' 1094 ]); 1095 $this->getDataGenerator()->create_user([ 1096 'institution' => 'University2' 1097 ]); 1098 1099 $results = external::get_users('University1'); 1100 $this->assertCount(1, $results); 1101 $this->assertEquals((object)[ 1102 'id' => $student1->id, 1103 'fullname' => fullname($student1), 1104 'extrafields' => [ 1105 0 => (object)[ 1106 'name' => 'institution', 1107 'value' => 'University1' 1108 ] 1109 ] 1110 ], $results[$student1->id]); 1111 } 1112 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body