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 mod_glossary 21 * @copyright 2018 Simey Lameze <simey@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 namespace mod_glossary\privacy; 25 26 use core_privacy\local\metadata\collection; 27 use core_privacy\local\request\approved_userlist; 28 use core_privacy\local\request\deletion_criteria; 29 use mod_glossary\privacy\provider; 30 31 defined('MOODLE_INTERNAL') || die(); 32 33 global $CFG; 34 require_once($CFG->dirroot . '/comment/lib.php'); 35 require_once($CFG->dirroot . '/rating/lib.php'); 36 37 /** 38 * Privacy provider tests class. 39 * 40 * @package mod_glossary 41 * @copyright 2018 Simey Lameze <simey@moodle.com> 42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 43 */ 44 class provider_test extends \core_privacy\tests\provider_testcase { 45 /** @var stdClass The student object. */ 46 protected $student; 47 48 /** @var stdClass The teacher object. */ 49 protected $teacher; 50 51 /** @var stdClass The glossary object. */ 52 protected $glossary; 53 54 /** @var stdClass The course object. */ 55 protected $course; 56 57 /** @var stdClass The plugin generator object. */ 58 protected $plugingenerator; 59 60 /** 61 * {@inheritdoc} 62 */ 63 protected function setUp(): void { 64 $this->resetAfterTest(); 65 66 global $DB; 67 $generator = $this->getDataGenerator(); 68 $course = $generator->create_course(); 69 $this->course = $course; 70 71 $this->plugingenerator = $generator->get_plugin_generator('mod_glossary'); 72 73 // The glossary activity the user will answer. 74 $glossary = $this->plugingenerator->create_instance(['course' => $course->id]); 75 $this->glossary = $glossary; 76 77 $cm = get_coursemodule_from_instance('glossary', $glossary->id); 78 $context = \context_module::instance($cm->id); 79 80 // Create a student which will add an entry to a glossary. 81 $student = $generator->create_user(); 82 $generator->enrol_user($student->id, $course->id, 'student'); 83 $this->student = $student; 84 85 $teacher = $generator->create_user(); 86 $generator->enrol_user($teacher->id, $course->id, 'editingteacher'); 87 $this->teacher = $teacher; 88 89 $this->setUser($student->id); 90 $ge1 = $this->plugingenerator->create_content($glossary, ['concept' => 'first', 'approved' => 1], ['one']); 91 92 // Student create a comment on a glossary entry. 93 $this->setUser($student); 94 $comment = $this->get_comment_object($context, $ge1->id); 95 $comment->add('Hello, it\'s me!'); 96 97 // Attach tags. 98 \core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge1->id, $context, ['Beer', 'Golf']); 99 } 100 101 /** 102 * Test for provider::get_metadata(). 103 */ 104 public function test_get_metadata() { 105 $collection = new collection('mod_glossary'); 106 $newcollection = provider::get_metadata($collection); 107 $itemcollection = $newcollection->get_collection(); 108 $this->assertCount(5, $itemcollection); 109 110 $table = reset($itemcollection); 111 $this->assertEquals('glossary_entries', $table->get_name()); 112 113 $privacyfields = $table->get_privacy_fields(); 114 $this->assertArrayHasKey('glossaryid', $privacyfields); 115 $this->assertArrayHasKey('concept', $privacyfields); 116 $this->assertArrayHasKey('definition', $privacyfields); 117 $this->assertArrayHasKey('attachment', $privacyfields); 118 $this->assertArrayHasKey('userid', $privacyfields); 119 $this->assertArrayHasKey('timemodified', $privacyfields); 120 121 $this->assertEquals('privacy:metadata:glossary_entries', $table->get_summary()); 122 } 123 124 /** 125 * Test for provider::get_contexts_for_userid(). 126 */ 127 public function test_get_contexts_for_userid() { 128 $cm = get_coursemodule_from_instance('glossary', $this->glossary->id); 129 130 $contextlist = provider::get_contexts_for_userid($this->student->id); 131 $this->assertCount(1, $contextlist); 132 $contextforuser = $contextlist->current(); 133 $cmcontext = \context_module::instance($cm->id); 134 $this->assertEquals($cmcontext->id, $contextforuser->id); 135 } 136 137 /** 138 * Test for provider::get_users_in_context(). 139 */ 140 public function test_get_users_in_context() { 141 $component = 'mod_glossary'; 142 $cm = get_coursemodule_from_instance('glossary', $this->glossary->id); 143 $cmcontext = \context_module::instance($cm->id); 144 145 $userlist = new \core_privacy\local\request\userlist($cmcontext, $component); 146 provider::get_users_in_context($userlist); 147 148 $this->assertCount(1, $userlist); 149 150 $expected = [$this->student->id]; 151 $actual = $userlist->get_userids(); 152 sort($expected); 153 sort($actual); 154 155 $this->assertEquals($expected, $actual); 156 } 157 158 /** 159 * Test for provider::export_user_data(). 160 */ 161 public function test_export_for_context() { 162 $cm = get_coursemodule_from_instance('glossary', $this->glossary->id); 163 $cmcontext = \context_module::instance($cm->id); 164 165 // Export all of the data for the context. 166 $writer = \core_privacy\local\request\writer::with_context($cmcontext); 167 $contextlist = new \core_privacy\local\request\approved_contextlist($this->student, 'mod_glossary' , [$cmcontext->id]); 168 169 \mod_glossary\privacy\provider::export_user_data($contextlist); 170 $this->assertTrue($writer->has_any_data()); 171 $data = $writer->get_data([]); 172 173 $this->assertEquals('Glossary 1', $data->name); 174 $this->assertEquals('first', $data->entries[0]['concept']); 175 } 176 177 /** 178 * Test for provider::delete_data_for_all_users_in_context(). 179 */ 180 public function test_delete_data_for_all_users_in_context() { 181 global $DB; 182 183 $generator = $this->getDataGenerator(); 184 $cm = get_coursemodule_from_instance('glossary', $this->glossary->id); 185 $context = \context_module::instance($cm->id); 186 // Create another student who will add an entry the glossary activity. 187 $student2 = $generator->create_user(); 188 $generator->enrol_user($student2->id, $this->course->id, 'student'); 189 190 $this->setUser($student2); 191 $ge3 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'first', 'approved' => 1], ['three']); 192 $comment = $this->get_comment_object($context, $ge3->id); 193 $comment->add('User 2 comment'); 194 195 $this->plugingenerator->create_category($this->glossary, ['cat1'], [$ge3]); 196 $count = $DB->count_records('glossary_entries_categories', ['entryid' => $ge3->id]); 197 $this->assertEquals(1, $count); 198 \core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context, ['Pizza', 'Noodles']); 199 200 // As a teacher, rate student 2 entry. 201 $this->setUser($this->teacher); 202 $rating = $this->get_rating_object($context, $ge3->id); 203 $rating->update_rating(2); 204 205 // Before deletion, we should have 2 entries. 206 $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]); 207 $this->assertEquals(2, $count); 208 $aliascount = $DB->count_records('glossary_alias'); 209 $this->assertEquals(2, $aliascount); 210 // Delete data based on context. 211 provider::delete_data_for_all_users_in_context($context); 212 213 // After deletion, the glossary entries and aliases for that glossary activity should have been deleted. 214 $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]); 215 $this->assertEquals(0, $count); 216 $this->assertEquals(0, $DB->count_records('glossary_alias')); 217 $count = $DB->count_records('glossary_entries_categories', ['entryid' => $ge3->id]); 218 $this->assertEquals(0, $count); 219 $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries', 220 'itemid' => $ge3->id]); 221 $this->assertEquals(0, $tagcount); 222 223 $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry', 224 'itemid' => $ge3->id, 'userid' => $student2->id]); 225 $this->assertEquals(0, $commentcount); 226 227 $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry', 228 'itemid' => $ge3->id]); 229 $this->assertEquals(0, $ratingcount); 230 } 231 232 /** 233 * Test for provider::delete_data_for_user(). 234 */ 235 public function test_delete_data_for_user() { 236 global $DB; 237 $generator = $this->getDataGenerator(); 238 239 // Create another student who will add an entry to the first glossary. 240 $student2 = $generator->create_user(); 241 $generator->enrol_user($student2->id, $this->course->id, 'student'); 242 243 $cm1 = get_coursemodule_from_instance('glossary', $this->glossary->id); 244 $glossary2 = $this->plugingenerator->create_instance(['course' => $this->course->id]); 245 $cm2 = get_coursemodule_from_instance('glossary', $glossary2->id); 246 247 $ge1 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'first user glossary entry', 'approved' => 1]); 248 $this->plugingenerator->create_content($glossary2, ['concept' => 'first user second glossary entry', 'approved' => 1]); 249 250 $context1 = \context_module::instance($cm1->id); 251 $context2 = \context_module::instance($cm2->id); 252 \core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge1->id, $context1, ['Parmi', 'Sushi']); 253 254 $this->setUser($student2); 255 $ge3 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'second user glossary entry', 256 'approved' => 1], ['three']); 257 258 $comment = $this->get_comment_object($context1, $ge3->id); 259 $comment->add('User 2 comment'); 260 261 \core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context1, ['Pizza', 'Noodles']); 262 263 // As a teacher, rate student 2's entry. 264 $this->setUser($this->teacher); 265 $rating = $this->get_rating_object($context1, $ge3->id); 266 $rating->update_rating(2); 267 268 // Before deletion, we should have 3 entries, one rating and 2 tag instances. 269 $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]); 270 $this->assertEquals(3, $count); 271 $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries', 272 'itemid' => $ge3->id]); 273 $this->assertEquals(2, $tagcount); 274 $aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge3->id]); 275 $this->assertEquals(1, $aliascount); 276 $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry', 277 'itemid' => $ge3->id]); 278 $this->assertEquals(1, $ratingcount); 279 280 $contextlist = new \core_privacy\local\request\approved_contextlist($student2, 'glossary', 281 [$context1->id, $context2->id]); 282 provider::delete_data_for_user($contextlist); 283 284 // After deletion, the glossary entry and tags for the second student should have been deleted. 285 $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id, 'userid' => $student2->id]); 286 $this->assertEquals(0, $count); 287 288 $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries', 289 'itemid' => $ge3->id]); 290 $this->assertEquals(0, $tagcount); 291 292 $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry', 293 'itemid' => $ge3->id, 'userid' => $student2->id]); 294 $this->assertEquals(0, $commentcount); 295 $aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge3->id]); 296 $this->assertEquals(0, $aliascount); 297 298 // Student's 1 entries, comments and tags should not be removed. 299 $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id, 300 'userid' => $this->student->id]); 301 $this->assertEquals(2, $count); 302 303 $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries', 304 'itemid' => $ge1->id]); 305 $this->assertEquals(2, $tagcount); 306 307 $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry', 308 'userid' => $this->student->id]); 309 $this->assertEquals(1, $commentcount); 310 311 $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry', 312 'itemid' => $ge3->id]); 313 $this->assertEquals(0, $ratingcount); 314 } 315 316 /** 317 * Test for provider::delete_data_for_users(). 318 */ 319 public function test_delete_data_for_users() { 320 global $DB; 321 $generator = $this->getDataGenerator(); 322 323 $student2 = $generator->create_user(); 324 $generator->enrol_user($student2->id, $this->course->id, 'student'); 325 326 $cm1 = get_coursemodule_from_instance('glossary', $this->glossary->id); 327 $glossary2 = $this->plugingenerator->create_instance(['course' => $this->course->id]); 328 $cm2 = get_coursemodule_from_instance('glossary', $glossary2->id); 329 330 $ge1 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'first user glossary entry', 'approved' => 1]); 331 $ge2 = $this->plugingenerator->create_content($glossary2, ['concept' => 'first user second glossary entry', 332 'approved' => 1], ['two']); 333 334 $context1 = \context_module::instance($cm1->id); 335 $context2 = \context_module::instance($cm2->id); 336 \core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge1->id, $context1, ['Parmi', 'Sushi']); 337 338 $this->setUser($student2); 339 $ge3 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'second user glossary entry', 340 'approved' => 1], ['three']); 341 342 $comment = $this->get_comment_object($context1, $ge3->id); 343 $comment->add('User 2 comment 1'); 344 $comment = $this->get_comment_object($context2, $ge2->id); 345 $comment->add('User 2 comment 2'); 346 347 \core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context1, ['Pizza', 'Noodles']); 348 \core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge2->id, $context2, ['Potato', 'Kumara']); 349 350 // As a teacher, rate student 2's entry. 351 $this->setUser($this->teacher); 352 $rating = $this->get_rating_object($context1, $ge3->id); 353 $rating->update_rating(2); 354 355 // Check correct glossary 1 record counts before deletion. 356 $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]); 357 // Note: There is an additional student entry from setUp(). 358 $this->assertEquals(3, $count); 359 360 list($context1itemsql, $context1itemparams) = $DB->get_in_or_equal([$ge1->id, $ge3->id], SQL_PARAMS_NAMED); 361 $geparams = [ 362 'component' => 'mod_glossary', 363 'itemtype' => 'glossary_entries', 364 ]; 365 $geparams += $context1itemparams; 366 $wheresql = "component = :component AND itemtype = :itemtype AND itemid {$context1itemsql}"; 367 368 $tagcount = $DB->count_records_select('tag_instance', $wheresql, $geparams); 369 $this->assertEquals(4, $tagcount); 370 371 $aliascount = $DB->count_records_select('glossary_alias', "entryid {$context1itemsql}", $context1itemparams); 372 $this->assertEquals(1, $aliascount); 373 374 $commentparams = [ 375 'component' => 'mod_glossary', 376 'commentarea' => 'glossary_entry', 377 ]; 378 $commentparams += $context1itemparams; 379 $commentwhere = "component = :component AND commentarea = :commentarea AND itemid {$context1itemsql}"; 380 381 $commentcount = $DB->count_records_select('comments', $commentwhere, $commentparams); 382 $this->assertEquals(1, $commentcount); 383 384 $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry', 385 'itemid' => $ge3->id]); 386 $this->assertEquals(1, $ratingcount); 387 388 // Perform deletion within context 1 for both students. 389 $approveduserlist = new approved_userlist($context1, 'mod_glossary', 390 [$this->student->id, $student2->id]); 391 provider::delete_data_for_users($approveduserlist); 392 393 // After deletion, all context 1 entries, tags and comment should be deleted. 394 $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]); 395 $this->assertEquals(0, $count); 396 397 $tagcount = $DB->count_records_select('tag_instance', $wheresql, $geparams); 398 $this->assertEquals(0, $tagcount); 399 400 $aliascount = $DB->count_records_select('glossary_alias', "entryid {$context1itemsql}", $context1itemparams); 401 $this->assertEquals(0, $aliascount); 402 403 $commentcount = $DB->count_records_select('comments', $commentwhere, $commentparams); 404 $this->assertEquals(0, $commentcount); 405 406 // Context 2 entries should remain intact. 407 $count = $DB->count_records('glossary_entries', ['glossaryid' => $glossary2->id]); 408 $this->assertEquals(1, $count); 409 410 $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries', 411 'itemid' => $ge2->id]); 412 $this->assertEquals(2, $tagcount); 413 414 $aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge2->id]); 415 $this->assertEquals(1, $aliascount); 416 417 $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry', 418 'itemid' => $ge2->id]); 419 $this->assertEquals(1, $commentcount); 420 421 $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry', 422 'itemid' => $ge3->id]); 423 $this->assertEquals(0, $ratingcount); 424 } 425 426 /** 427 * Get the comment area for glossary module. 428 * 429 * @param context $context The context. 430 * @param int $itemid The item ID. 431 * @return comment 432 */ 433 protected function get_comment_object(\context $context, $itemid) { 434 $args = new \stdClass(); 435 436 $args->context = $context; 437 $args->course = get_course(SITEID); 438 $args->area = 'glossary_entry'; 439 $args->itemid = $itemid; 440 $args->component = 'mod_glossary'; 441 $comment = new \comment($args); 442 $comment->set_post_permission(true); 443 444 return $comment; 445 } 446 447 /** 448 * Get the rating area for glossary module. 449 * 450 * @param context $context The context. 451 * @param int $itemid The item ID. 452 * @return rating object 453 */ 454 protected function get_rating_object(\context $context, $itemid) { 455 global $USER; 456 457 $ratingoptions = new \stdClass; 458 $ratingoptions->context = $context; 459 $ratingoptions->ratingarea = 'entry'; 460 $ratingoptions->component = 'mod_glossary'; 461 $ratingoptions->itemid = $itemid; 462 $ratingoptions->scaleid = 2; 463 $ratingoptions->userid = $USER->id; 464 return new \rating($ratingoptions); 465 } 466 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body