Differences Between: [Versions 311 and 402] [Versions 311 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 /** 18 * Privacy provider tests. 19 * 20 * @package block_comments 21 * @copyright 2018 Shamim Rezaie <shamim@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 namespace block_comments\privacy; 25 26 use core_privacy\local\metadata\collection; 27 use block_comments\privacy\provider; 28 use core_privacy\local\request\approved_userlist; 29 30 defined('MOODLE_INTERNAL') || die(); 31 32 /** 33 * Privacy provider test for block_comments. 34 * 35 * @copyright 2018 Shamim Rezaie <shamim@moodle.com> 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class provider_test extends \core_privacy\tests\provider_testcase { 39 40 /** @var stdClass A student who is only enrolled in course1. */ 41 protected $student1; 42 43 /** @var stdClass A student who is only enrolled in course2. */ 44 protected $student2; 45 46 /** @var stdClass A student who is enrolled in both course1 and course2. */ 47 protected $student12; 48 49 /** @var stdClass A test course. */ 50 protected $course1; 51 52 /** @var stdClass A test course. */ 53 protected $course2; 54 55 protected function setUp(): void { 56 global $DB; 57 58 $this->resetAfterTest(); 59 $this->setAdminUser(); 60 61 // Create courses. 62 $generator = $this->getDataGenerator(); 63 $this->course1 = $generator->create_course(); 64 $this->course2 = $generator->create_course(); 65 66 // Create and enrol students. 67 $this->student1 = $generator->create_user(); 68 $this->student2 = $generator->create_user(); 69 $this->student12 = $generator->create_user(); 70 71 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 72 $generator->enrol_user($this->student1->id, $this->course1->id, $studentrole->id); 73 $generator->enrol_user($this->student2->id, $this->course2->id, $studentrole->id); 74 $generator->enrol_user($this->student12->id, $this->course1->id, $studentrole->id); 75 $generator->enrol_user($this->student12->id, $this->course2->id, $studentrole->id); 76 77 // Comment block on course pages. 78 $block = $this->add_comments_block_in_context(\context_course::instance($this->course1->id)); 79 $block = $this->add_comments_block_in_context(\context_course::instance($this->course2->id)); 80 } 81 82 /** 83 * Posts a comment on a given context. 84 * 85 * @param string $text The comment's text. 86 * @param context $context The context on which we want to put the comment. 87 */ 88 protected function add_comment($text, \context $context) { 89 $args = new \stdClass; 90 $args->context = $context; 91 $args->area = 'page_comments'; 92 $args->itemid = 0; 93 $args->component = 'block_comments'; 94 $args->linktext = get_string('showcomments'); 95 $args->notoggle = true; 96 $args->autostart = true; 97 $args->displaycancel = false; 98 $comment = new \comment($args); 99 100 $comment->add($text); 101 } 102 103 /** 104 * Creates a comments block on a context. 105 * 106 * @param context $context The context on which we want to put the block. 107 * @return block_base The created block instance. 108 * @throws coding_exception 109 */ 110 protected function add_comments_block_in_context(\context $context) { 111 global $DB; 112 113 $course = null; 114 115 $page = new \moodle_page(); 116 $page->set_context($context); 117 118 switch ($context->contextlevel) { 119 case CONTEXT_SYSTEM: 120 $page->set_pagelayout('frontpage'); 121 $page->set_pagetype('site-index'); 122 break; 123 case CONTEXT_COURSE: 124 $page->set_pagelayout('standard'); 125 $page->set_pagetype('course-view'); 126 $course = $DB->get_record('course', ['id' => $context->instanceid]); 127 $page->set_course($course); 128 break; 129 case CONTEXT_MODULE: 130 $page->set_pagelayout('standard'); 131 $mod = $DB->get_field_sql("SELECT m.name 132 FROM {modules} m 133 JOIN {course_modules} cm on cm.module = m.id 134 WHERE cm.id = ?", [$context->instanceid]); 135 $page->set_pagetype("mod-$mod-view"); 136 break; 137 case CONTEXT_USER: 138 $page->set_pagelayout('mydashboard'); 139 $page->set_pagetype('my-index'); 140 break; 141 default: 142 throw new coding_exception('Unsupported context for test'); 143 } 144 145 $page->blocks->load_blocks(); 146 147 $page->blocks->add_block_at_end_of_default_region('comments'); 148 149 // We need to use another page object as load_blocks() only loads the blocks once. 150 $page2 = new \moodle_page(); 151 $page2->set_context($page->context); 152 $page2->set_pagelayout($page->pagelayout); 153 $page2->set_pagetype($page->pagetype); 154 if ($course) { 155 $page2->set_course($course); 156 } 157 158 $page->blocks->load_blocks(); 159 $page2->blocks->load_blocks(); 160 $blocks = $page2->blocks->get_blocks_for_region($page2->blocks->get_default_region()); 161 $block = end($blocks); 162 163 $block = block_instance('comments', $block->instance); 164 165 return $block; 166 } 167 168 /** 169 * Test for provider::get_metadata(). 170 */ 171 public function test_get_metadata() { 172 $collection = new collection('block_comments'); 173 $newcollection = provider::get_metadata($collection); 174 $itemcollection = $newcollection->get_collection(); 175 $this->assertCount(1, $itemcollection); 176 177 $link = reset($itemcollection); 178 179 $this->assertEquals('core_comment', $link->get_name()); 180 $this->assertEmpty($link->get_privacy_fields()); 181 $this->assertEquals('privacy:metadata:core_comment', $link->get_summary()); 182 } 183 184 /** 185 * Test for provider::get_contexts_for_userid() when user had not posted any comments.. 186 */ 187 public function test_get_contexts_for_userid_no_comment() { 188 $this->setUser($this->student1); 189 $coursecontext1 = \context_course::instance($this->course1->id); 190 $this->add_comment('New comment', $coursecontext1); 191 192 $this->setUser($this->student2); 193 $contextlist = provider::get_contexts_for_userid($this->student2->id); 194 $this->assertCount(0, $contextlist); 195 } 196 197 /** 198 * Test for provider::get_contexts_for_userid(). 199 */ 200 public function test_get_contexts_for_userid() { 201 $coursecontext1 = \context_course::instance($this->course1->id); 202 $coursecontext2 = \context_course::instance($this->course2->id); 203 204 $this->setUser($this->student12); 205 $this->add_comment('New comment', $coursecontext1); 206 $this->add_comment('New comment', $coursecontext1); 207 $this->add_comment('New comment', $coursecontext2); 208 209 $contextlist = provider::get_contexts_for_userid($this->student12->id); 210 $this->assertCount(2, $contextlist); 211 212 $contextids = $contextlist->get_contextids(); 213 $this->assertEqualsCanonicalizing([$coursecontext1->id, $coursecontext2->id], $contextids); 214 } 215 216 /** 217 * Test for provider::export_user_data() when the user has not posted any comments. 218 */ 219 public function test_export_for_context_no_comment() { 220 $coursecontext1 = \context_course::instance($this->course1->id); 221 $coursecontext2 = \context_course::instance($this->course2->id); 222 223 $this->setUser($this->student1); 224 $this->add_comment('New comment', $coursecontext1); 225 226 $this->setUser($this->student2); 227 228 $this->setUser($this->student2); 229 $this->export_context_data_for_user($this->student2->id, $coursecontext2, 'block_comments'); 230 $writer = \core_privacy\local\request\writer::with_context($coursecontext2); 231 $this->assertFalse($writer->has_any_data()); 232 233 } 234 235 /** 236 * Test for provider::export_user_data(). 237 */ 238 public function test_export_for_context() { 239 $coursecontext1 = \context_course::instance($this->course1->id); 240 $coursecontext2 = \context_course::instance($this->course2->id); 241 242 $this->setUser($this->student12); 243 $this->add_comment('New comment', $coursecontext1); 244 $this->add_comment('New comment', $coursecontext1); 245 $this->add_comment('New comment', $coursecontext2); 246 247 // Export all of the data for the context. 248 $this->export_context_data_for_user($this->student12->id, $coursecontext1, 'block_comments'); 249 $writer = \core_privacy\local\request\writer::with_context($coursecontext1); 250 $this->assertTrue($writer->has_any_data()); 251 } 252 253 /** 254 * Test for provider::delete_data_for_all_users_in_context(). 255 */ 256 public function test_delete_data_for_all_users_in_context() { 257 global $DB; 258 259 $coursecontext1 = \context_course::instance($this->course1->id); 260 $coursecontext2 = \context_course::instance($this->course2->id); 261 262 $this->setUser($this->student1); 263 $this->add_comment('New comment', $coursecontext1); 264 265 $this->setUser($this->student2); 266 $this->add_comment('New comment', $coursecontext2); 267 268 $this->setUser($this->student12); 269 $this->add_comment('New comment', $coursecontext1); 270 $this->add_comment('New comment', $coursecontext1); 271 $this->add_comment('New comment', $coursecontext2); 272 273 // Before deletion, we should have 3 comments in $coursecontext1 and 2 comments in $coursecontext2. 274 $this->assertEquals( 275 3, 276 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id]) 277 ); 278 $this->assertEquals( 279 2, 280 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id]) 281 ); 282 283 // Delete data based on context. 284 provider::delete_data_for_all_users_in_context($coursecontext1); 285 286 // After deletion, the comments for $coursecontext1 should have been deleted. 287 $this->assertEquals( 288 0, 289 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id]) 290 ); 291 $this->assertEquals( 292 2, 293 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id]) 294 ); 295 } 296 297 /** 298 * Test for provider::delete_data_for_all_users_in_context() when there are also comments from other plugins. 299 */ 300 public function test_delete_data_for_all_users_in_context_with_comments_from_other_plugins() { 301 global $DB; 302 303 $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 304 $instance = $assigngenerator->create_instance(['course' => $this->course1]); 305 $cm = get_coursemodule_from_instance('assign', $instance->id); 306 $assigncontext = \context_module::instance($cm->id); 307 $assign = new \assign($assigncontext, $cm, $this->course1); 308 309 // Add a comments block in the assignment page. 310 $this->add_comments_block_in_context($assigncontext); 311 312 $submission = $assign->get_user_submission($this->student1->id, true); 313 314 $options = new \stdClass(); 315 $options->area = 'submission_comments'; 316 $options->course = $assign->get_course(); 317 $options->context = $assigncontext; 318 $options->itemid = $submission->id; 319 $options->component = 'assignsubmission_comments'; 320 $options->showcount = true; 321 $options->displaycancel = true; 322 323 $comment = new \comment($options); 324 $comment->set_post_permission(true); 325 326 $this->setUser($this->student1); 327 $comment->add('Comment from student 1'); 328 329 $this->add_comment('New comment', $assigncontext); 330 331 $this->setUser($this->student2); 332 $this->add_comment('New comment', $assigncontext); 333 334 // Before deletion, we should have 3 comments in $assigncontext. 335 // One comment is for the assignment submission and 2 are for the comments block. 336 $this->assertEquals( 337 3, 338 $DB->count_records('comments', ['contextid' => $assigncontext->id]) 339 ); 340 $this->assertEquals( 341 2, 342 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $assigncontext->id]) 343 ); 344 345 provider::delete_data_for_all_users_in_context($assigncontext); 346 347 // After deletion, the comments for $assigncontext in the comment block should have been deleted, 348 // but the assignment submission comment should be left. 349 $this->assertEquals( 350 1, 351 $DB->count_records('comments', ['contextid' => $assigncontext->id]) 352 ); 353 $this->assertEquals( 354 0, 355 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $assigncontext->id]) 356 ); 357 } 358 359 /** 360 * Test for provider::delete_data_for_user(). 361 */ 362 public function test_delete_data_for_user() { 363 global $DB; 364 365 $coursecontext1 = \context_course::instance($this->course1->id); 366 $coursecontext2 = \context_course::instance($this->course2->id); 367 368 $this->setUser($this->student1); 369 $this->add_comment('New comment', $coursecontext1); 370 371 $this->setUser($this->student2); 372 $this->add_comment('New comment', $coursecontext2); 373 374 $this->setUser($this->student12); 375 $this->add_comment('New comment', $coursecontext1); 376 $this->add_comment('New comment', $coursecontext1); 377 $this->add_comment('New comment', $coursecontext2); 378 379 // Before deletion, we should have 3 comments in $coursecontext1 and 2 comments in $coursecontext2, 380 // and 3 comments by student12 in $coursecontext1 and $coursecontext2 combined. 381 $this->assertEquals( 382 3, 383 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id]) 384 ); 385 $this->assertEquals( 386 2, 387 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id]) 388 ); 389 $this->assertEquals( 390 3, 391 $DB->count_records('comments', ['component' => 'block_comments', 'userid' => $this->student12->id]) 392 ); 393 394 $contextlist = new \core_privacy\local\request\approved_contextlist($this->student12, 'block_comments', 395 [$coursecontext1->id, $coursecontext2->id]); 396 provider::delete_data_for_user($contextlist); 397 398 // After deletion, the comments for the student12 should have been deleted. 399 $this->assertEquals( 400 1, 401 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext1->id]) 402 ); 403 $this->assertEquals( 404 1, 405 $DB->count_records('comments', ['component' => 'block_comments', 'contextid' => $coursecontext2->id]) 406 ); 407 $this->assertEquals( 408 0, 409 $DB->count_records('comments', ['component' => 'block_comments', 'userid' => $this->student12->id]) 410 ); 411 } 412 413 /** 414 * Test for provider::delete_data_for_user() when there are also comments from other plugins. 415 */ 416 public function test_delete_data_for_user_with_comments_from_other_plugins() { 417 global $DB; 418 419 $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 420 $instance = $assigngenerator->create_instance(['course' => $this->course1]); 421 $cm = get_coursemodule_from_instance('assign', $instance->id); 422 $assigncontext = \context_module::instance($cm->id); 423 $assign = new \assign($assigncontext, $cm, $this->course1); 424 425 // Add a comments block in the assignment page. 426 $this->add_comments_block_in_context($assigncontext); 427 428 $submission = $assign->get_user_submission($this->student1->id, true); 429 430 $options = new \stdClass(); 431 $options->area = 'submission_comments'; 432 $options->course = $assign->get_course(); 433 $options->context = $assigncontext; 434 $options->itemid = $submission->id; 435 $options->component = 'assignsubmission_comments'; 436 $options->showcount = true; 437 $options->displaycancel = true; 438 439 $comment = new \comment($options); 440 $comment->set_post_permission(true); 441 442 $this->setUser($this->student1); 443 $comment->add('Comment from student 1'); 444 445 $this->add_comment('New comment', $assigncontext); 446 $this->add_comment('New comment', $assigncontext); 447 448 // Before deletion, we should have 3 comments in $assigncontext. 449 // one comment is for the assignment submission and 2 are for the comments block. 450 $this->assertEquals( 451 3, 452 $DB->count_records('comments', ['contextid' => $assigncontext->id]) 453 ); 454 455 $contextlist = new \core_privacy\local\request\approved_contextlist($this->student1, 'block_comments', 456 [$assigncontext->id]); 457 provider::delete_data_for_user($contextlist); 458 459 // After deletion, the comments for the student1 in the comment block should have been deleted, 460 // but the assignment submission comment should be left. 461 $this->assertEquals( 462 1, 463 $DB->count_records('comments', ['contextid' => $assigncontext->id]) 464 ); 465 $this->assertEquals( 466 0, 467 $DB->count_records('comments', ['component' => 'block_comments', 'userid' => $this->student1->id]) 468 ); 469 } 470 471 /** 472 * Test that only users within a course context are fetched. 473 * @group qtesttt 474 */ 475 public function test_get_users_in_context() { 476 $component = 'block_comments'; 477 478 $coursecontext1 = \context_course::instance($this->course1->id); 479 $coursecontext2 = \context_course::instance($this->course2->id); 480 481 $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); 482 provider::get_users_in_context($userlist1); 483 $this->assertCount(0, $userlist1); 484 485 $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); 486 provider::get_users_in_context($userlist2); 487 $this->assertCount(0, $userlist2); 488 489 $this->setUser($this->student12); 490 $this->add_comment('New comment', $coursecontext1); 491 $this->add_comment('New comment', $coursecontext2); 492 $this->setUser($this->student1); 493 $this->add_comment('New comment', $coursecontext1); 494 495 // The list of users should contain user12 and user1. 496 provider::get_users_in_context($userlist1); 497 $this->assertCount(2, $userlist1); 498 $this->assertTrue(in_array($this->student1->id, $userlist1->get_userids())); 499 $this->assertTrue(in_array($this->student12->id, $userlist1->get_userids())); 500 501 // The list of users should contain user12. 502 provider::get_users_in_context($userlist2); 503 $this->assertCount(1, $userlist2); 504 $expected = [$this->student12->id]; 505 $actual = $userlist2->get_userids(); 506 $this->assertEquals($expected, $actual); 507 } 508 509 /** 510 * Test that data for users in approved userlist is deleted. 511 */ 512 public function test_delete_data_for_users() { 513 $component = 'block_comments'; 514 515 $coursecontext1 = \context_course::instance($this->course1->id); 516 $coursecontext2 = \context_course::instance($this->course2->id); 517 518 $this->setUser($this->student12); 519 $this->add_comment('New comment', $coursecontext1); 520 $this->add_comment('New comment', $coursecontext2); 521 $this->setUser($this->student1); 522 $this->add_comment('New comment', $coursecontext1); 523 524 $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); 525 provider::get_users_in_context($userlist1); 526 $this->assertCount(2, $userlist1); 527 528 $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); 529 provider::get_users_in_context($userlist2); 530 $this->assertCount(1, $userlist2); 531 532 // Convert $userlist1 into an approved_contextlist. 533 $approvedlist1 = new approved_userlist($coursecontext1, $component, $userlist1->get_userids()); 534 // Delete using delete_data_for_user. 535 provider::delete_data_for_users($approvedlist1); 536 537 // Re-fetch users in coursecontext1. 538 $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component); 539 provider::get_users_in_context($userlist1); 540 // The user data in coursecontext1 should be deleted. 541 $this->assertCount(0, $userlist1); 542 543 // Re-fetch users in coursecontext2. 544 $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component); 545 provider::get_users_in_context($userlist2); 546 // The user data in coursecontext2 should be still present. 547 $this->assertCount(1, $userlist2); 548 } 549 550 /** 551 * Test for provider::delete_data_for_user() when there are also comments from other plugins. 552 */ 553 public function test_delete_data_for_users_with_comments_from_other_plugins() { 554 $component = 'block_comments'; 555 556 $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 557 $instance = $assigngenerator->create_instance(['course' => $this->course1]); 558 $cm = get_coursemodule_from_instance('assign', $instance->id); 559 $assigncontext = \context_module::instance($cm->id); 560 $assign = new \assign($assigncontext, $cm, $this->course1); 561 562 // Add a comments block in the assignment page. 563 $this->add_comments_block_in_context($assigncontext); 564 565 $submission = $assign->get_user_submission($this->student1->id, true); 566 567 $options = new \stdClass(); 568 $options->area = 'submission_comments'; 569 $options->course = $assign->get_course(); 570 $options->context = $assigncontext; 571 $options->itemid = $submission->id; 572 $options->component = 'assignsubmission_comments'; 573 $options->showcount = true; 574 $options->displaycancel = true; 575 576 $comment = new \comment($options); 577 $comment->set_post_permission(true); 578 579 $this->setUser($this->student1); 580 $comment->add('Comment from student 1'); 581 582 $this->add_comment('New comment', $assigncontext); 583 $this->add_comment('New comment', $assigncontext); 584 585 $userlist1 = new \core_privacy\local\request\userlist($assigncontext, $component); 586 provider::get_users_in_context($userlist1); 587 $this->assertCount(1, $userlist1); 588 589 // Convert $userlist1 into an approved_contextlist. 590 $approvedlist = new approved_userlist($assigncontext, $component, $userlist1->get_userids()); 591 // Delete using delete_data_for_user. 592 provider::delete_data_for_users($approvedlist); 593 594 // Re-fetch users in assigncontext. 595 $userlist1 = new \core_privacy\local\request\userlist($assigncontext, $component); 596 provider::get_users_in_context($userlist1); 597 // The user data in assigncontext should be deleted. 598 $this->assertCount(0, $userlist1); 599 } 600 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body