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 * Privacy tests for core_course. 18 * 19 * @package core_course 20 * @category test 21 * @copyright 2018 Adrian Greeve <adrian@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 global $CFG; 28 require_once($CFG->dirroot . '/completion/tests/fixtures/completion_creation.php'); 29 30 use \core_privacy\local\request\transform; 31 32 /** 33 * Unit tests for course/classes/privacy/policy 34 * 35 * @copyright 2018 Adrian Greeve <adrian@moodle.com> 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class core_course_privacy_testcase extends \core_privacy\tests\provider_testcase { 39 40 use completion_creation; 41 42 /** 43 * Test getting the appropriate context for the userid. This should only ever 44 * return the user context for the user id supplied. 45 */ 46 public function test_get_contexts_for_userid() { 47 $this->resetAfterTest(); 48 49 $user1 = $this->getDataGenerator()->create_user(); 50 $user2 = $this->getDataGenerator()->create_user(); 51 52 // Make sure contexts are not being returned for user1. 53 $contextlist = \core_course\privacy\provider::get_contexts_for_userid($user1->id); 54 $this->assertCount(0, $contextlist->get_contextids()); 55 56 // Make sure contexts are not being returned for user2. 57 $contextlist = \core_course\privacy\provider::get_contexts_for_userid($user2->id); 58 $this->assertCount(0, $contextlist->get_contextids()); 59 60 // Create course completion data for user1. 61 $this->create_course_completion(); 62 $this->complete_course($user1); 63 64 // Make sure the course context is being returned for user1. 65 $contextlist = \core_course\privacy\provider::get_contexts_for_userid($user1->id); 66 $expected = [$this->coursecontext->id]; 67 $actual = $contextlist->get_contextids(); 68 $this->assertCount(1, $actual); 69 $this->assertEquals($expected, $actual); 70 71 // Make sure contexts are still not being returned for user2. 72 $contextlist = \core_course\privacy\provider::get_contexts_for_userid($user2->id); 73 $this->assertCount(0, $contextlist->get_contextids()); 74 75 // User2 has a favourite course. 76 $user2context = \context_user::instance($user2->id); 77 $ufservice = \core_favourites\service_factory::get_service_for_user_context($user2context); 78 $ufservice->create_favourite('core_course', 'courses', $this->coursecontext->instanceid, 79 $this->coursecontext); 80 81 // Make sure the course context is being returned for user2. 82 $contextlist = \core_course\privacy\provider::get_contexts_for_userid($user2->id); 83 $expected = [$this->coursecontext->id]; 84 $actual = $contextlist->get_contextids(); 85 $this->assertCount(1, $actual); 86 $this->assertEquals($expected, $actual); 87 } 88 89 /** 90 * Test fetching users within a context. 91 */ 92 public function test_get_users_in_context() { 93 $this->resetAfterTest(); 94 $component = 'core_course'; 95 96 $user1 = $this->getDataGenerator()->create_user(); 97 $user2 = $this->getDataGenerator()->create_user(); 98 $user3 = $this->getDataGenerator()->create_user(); 99 $user4 = $this->getDataGenerator()->create_user(); 100 101 // User1 and user2 complete course. 102 $this->create_course_completion(); 103 $this->complete_course($user1); 104 $this->complete_course($user2); 105 106 // User3 is enrolled but has not completed course. 107 $this->getDataGenerator()->enrol_user($user3->id, $this->course->id, 'student'); 108 109 // User4 has a favourited course. 110 $systemcontext = \context_system::instance(); 111 $user4ctx = \context_user::instance($user4->id); 112 $ufservice = \core_favourites\service_factory::get_service_for_user_context($user4ctx); 113 $ufservice->create_favourite('core_course', 'courses', $this->coursecontext->instanceid, 114 $this->coursecontext); 115 116 // Ensure only users that have course completion or favourites are returned. 117 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, $component); 118 \core_course\privacy\provider::get_users_in_context($userlist); 119 $expected = [ 120 $user1->id, 121 $user2->id, 122 $user4->id 123 ]; 124 $actual = $userlist->get_userids(); 125 sort($expected); 126 sort($actual); 127 $this->assertCount(3, $actual); 128 $this->assertEquals($expected, $actual); 129 130 // Ensure that users are not being returned in other contexts than the course context. 131 $userlist = new \core_privacy\local\request\userlist($systemcontext, $component); 132 \core_course\privacy\provider::get_users_in_context($userlist); 133 $actual = $userlist->get_userids(); 134 $this->assertCount(0, $actual); 135 } 136 137 /** 138 * Test that user data is exported. 139 */ 140 public function test_export_user_data() { 141 $this->resetAfterTest(); 142 143 $user = $this->getDataGenerator()->create_user(); 144 $this->create_course_completion(); 145 $this->complete_course($user); 146 $approvedlist = new \core_privacy\local\request\approved_contextlist($user, 'core_course', 147 [$this->coursecontext->id]); 148 $writer = \core_privacy\local\request\writer::with_context($this->coursecontext); 149 \core_course\privacy\provider::export_user_data($approvedlist); 150 $completiondata = $writer->get_data([get_string('privacy:completionpath', 'course')]); 151 $this->assertEquals('In progress', $completiondata->status); 152 $this->assertCount(2, $completiondata->criteria); 153 154 // User has a favourite course. 155 $usercontext = \context_user::instance($user->id); 156 $ufservice = \core_favourites\service_factory::get_service_for_user_context($usercontext); 157 $favourite = $ufservice->create_favourite('core_course', 'courses', 158 $this->coursecontext->instanceid, $this->coursecontext); 159 160 // Ensure that user's favourites data in the course context is being exported. 161 $writer = \core_privacy\local\request\writer::with_context($this->coursecontext); 162 \core_course\privacy\provider::export_user_data($approvedlist); 163 $favouritedata = $writer->get_data([get_string('privacy:favouritespath', 'course')]); 164 165 $this->assertEquals(transform::yesno(true), $favouritedata->starred); 166 $this->assertEquals('', $favouritedata->ordering); 167 $this->assertEquals(transform::datetime($favourite->timecreated), $favouritedata->timecreated); 168 $this->assertEquals(transform::datetime($favourite->timemodified), $favouritedata->timemodified); 169 } 170 171 /** 172 * Verify that if a module context is included in the contextlist_collection and its parent course is not, the 173 * export_context_data() call picks this up, and that the contextual course information is included. 174 */ 175 public function test_export_context_data_module_context_only() { 176 $this->resetAfterTest(); 177 178 // Create a course and a single module. 179 $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course 1', 'shortname' => 'C1']); 180 $context1 = context_course::instance($course1->id); 181 $modassign = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id, 'name' => 'assign test 1']); 182 $assigncontext = context_module::instance($modassign->cmid); 183 184 // Now, let's assume during user info export, only the coursemodule context is returned in the contextlist_collection. 185 $user = $this->getDataGenerator()->create_user(); 186 $collection = new \core_privacy\local\request\contextlist_collection($user->id); 187 $approvedlist = new \core_privacy\local\request\approved_contextlist($user, 'mod_assign', [$assigncontext->id]); 188 $collection->add_contextlist($approvedlist); 189 190 // Now, verify that core_course will detect this, and add relevant contextual information. 191 \core_course\privacy\provider::export_context_data($collection); 192 $writer = \core_privacy\local\request\writer::with_context($context1); 193 $this->assertTrue($writer->has_any_data()); 194 $writerdata = $writer->get_data(); 195 $this->assertObjectHasAttribute('fullname', $writerdata); 196 $this->assertObjectHasAttribute('shortname', $writerdata); 197 $this->assertObjectHasAttribute('idnumber', $writerdata); 198 $this->assertObjectHasAttribute('summary', $writerdata); 199 } 200 201 /** 202 * Verify that if a module context and its parent course context are both included in the contextlist_collection, that course 203 * contextual information is present in the export. 204 */ 205 public function test_export_context_data_course_and_module_contexts() { 206 $this->resetAfterTest(); 207 208 // Create a course and a single module. 209 $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course 1', 'shortname' => 'C1', 'format' => 'site']); 210 $context1 = context_course::instance($course1->id); 211 $modassign = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id, 'name' => 'assign test 1']); 212 $assigncontext = context_module::instance($modassign->cmid); 213 214 // Now, assume during user info export, that both module and course contexts are returned in the contextlist_collection. 215 $user = $this->getDataGenerator()->create_user(); 216 $collection = new \core_privacy\local\request\contextlist_collection($user->id); 217 $approvedlist = new \core_privacy\local\request\approved_contextlist($user, 'mod_assign', [$assigncontext->id]); 218 $approvedlist2 = new \core_privacy\local\request\approved_contextlist($user, 'core_course', [$context1->id]); 219 $collection->add_contextlist($approvedlist); 220 $collection->add_contextlist($approvedlist2); 221 222 // Now, verify that core_course still adds relevant contextual information, even for courses which are explicitly listed in 223 // the contextlist_collection. 224 \core_course\privacy\provider::export_context_data($collection); 225 $writer = \core_privacy\local\request\writer::with_context($context1); 226 $this->assertTrue($writer->has_any_data()); 227 $writerdata = $writer->get_data(); 228 $this->assertObjectHasAttribute('fullname', $writerdata); 229 $this->assertObjectHasAttribute('shortname', $writerdata); 230 $this->assertObjectHasAttribute('idnumber', $writerdata); 231 $this->assertObjectHasAttribute('summary', $writerdata); 232 } 233 234 /** 235 * Test deleting all user data for one context. 236 */ 237 public function test_delete_data_for_all_users_in_context() { 238 global $DB; 239 240 $this->resetAfterTest(); 241 242 $user1 = $this->getDataGenerator()->create_user(); 243 $user2 = $this->getDataGenerator()->create_user(); 244 $this->create_course_completion(); 245 246 $systemcontext = \context_system::instance(); 247 $user1ctx = \context_user::instance($user1->id); 248 $user2ctx = \context_user::instance($user2->id); 249 // User1 and user2 have a favourite course. 250 $ufservice1 = \core_favourites\service_factory::get_service_for_user_context($user1ctx); 251 $ufservice1->create_favourite('core_course', 'courses', $this->coursecontext->instanceid, 252 $this->coursecontext); 253 $ufservice2 = \core_favourites\service_factory::get_service_for_user_context($user2ctx); 254 $ufservice2->create_favourite('core_course', 'courses', $this->coursecontext->instanceid, 255 $this->coursecontext); 256 257 // Ensure only users that have course favourites are returned in the course context (user1 and user2). 258 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 259 \core_course\privacy\provider::get_users_in_context($userlist); 260 $actual = $userlist->get_userids(); 261 $this->assertCount(2, $actual); 262 263 // Ensure the users does not have a course completion data. 264 $records = $DB->get_records('course_modules_completion'); 265 $this->assertCount(0, $records); 266 $records = $DB->get_records('course_completion_crit_compl'); 267 $this->assertCount(0, $records); 268 269 // Create course completions for user1 and users. 270 $this->complete_course($user1); 271 $this->complete_course($user2); 272 $records = $DB->get_records('course_modules_completion'); 273 $this->assertCount(2, $records); 274 $records = $DB->get_records('course_completion_crit_compl'); 275 $this->assertCount(2, $records); 276 277 // Delete data for all users in a context different than the course context (system context). 278 \core_course\privacy\provider::delete_data_for_all_users_in_context($systemcontext); 279 280 // Ensure the data in the course context has not been deleted. 281 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 282 \core_course\privacy\provider::get_users_in_context($userlist); 283 $actual = $userlist->get_userids(); 284 $this->assertCount(2, $actual); 285 286 // Delete data for all users in the course context. 287 \core_course\privacy\provider::delete_data_for_all_users_in_context($this->coursecontext); 288 289 // Ensure the completion data has been removed in the course context. 290 $records = $DB->get_records('course_modules_completion'); 291 $this->assertCount(0, $records); 292 $records = $DB->get_records('course_completion_crit_compl'); 293 $this->assertCount(0, $records); 294 295 // Ensure that users are not returned after the deletion in the course context. 296 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 297 \core_course\privacy\provider::get_users_in_context($userlist); 298 $actual = $userlist->get_userids(); 299 $this->assertCount(0, $actual); 300 } 301 302 /** 303 * Test deleting data for only one user. 304 */ 305 public function test_delete_data_for_user() { 306 $this->resetAfterTest(); 307 308 $user1 = $this->getDataGenerator()->create_user(); 309 $user2 = $this->getDataGenerator()->create_user(); 310 $user3 = $this->getDataGenerator()->create_user(); 311 312 // Create course completion for user1. 313 $this->create_course_completion(); 314 $this->complete_course($user1); 315 316 // Ensure user1 is returned in the course context. 317 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 318 \core_course\privacy\provider::get_users_in_context($userlist); 319 $actual = $userlist->get_userids(); 320 $expected = [$user1->id]; 321 $this->assertCount(1, $actual); 322 $this->assertEquals($expected, $actual); 323 324 // User2 and user3 have a favourite course. 325 $systemcontext = \context_system::instance(); 326 $user2ctx = \context_user::instance($user2->id); 327 $user3ctx = \context_user::instance($user3->id); 328 $ufservice2 = \core_favourites\service_factory::get_service_for_user_context($user2ctx); 329 $ufservice2->create_favourite('core_course', 'courses', $this->coursecontext->instanceid, 330 $this->coursecontext); 331 $ufservice3 = \core_favourites\service_factory::get_service_for_user_context($user3ctx); 332 $ufservice3->create_favourite('core_course', 'courses', $this->coursecontext->instanceid, 333 $this->coursecontext); 334 335 // Ensure user1, user2 and user3 are returned in the course context. 336 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 337 \core_course\privacy\provider::get_users_in_context($userlist); 338 $actual = $userlist->get_userids(); 339 $expected = [ 340 $user1->id, 341 $user2->id, 342 $user3->id 343 ]; 344 sort($expected); 345 sort($actual); 346 $this->assertCount(3, $actual); 347 $this->assertEquals($expected, $actual); 348 349 // Delete user1's data in the course context. 350 $approvedlist = new \core_privacy\local\request\approved_contextlist($user1, 'core_course', 351 [$this->coursecontext->id]); 352 \core_course\privacy\provider::delete_data_for_user($approvedlist); 353 354 // Ensure user1's data is deleted and only user2 and user3 are returned in the course context. 355 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 356 \core_course\privacy\provider::get_users_in_context($userlist); 357 $actual = $userlist->get_userids(); 358 $expected = [ 359 $user2->id, 360 $user3->id 361 ]; 362 sort($expected); 363 sort($actual); 364 $this->assertEquals($expected, $actual); 365 366 // Delete user2's data in a context different than the course context (system context). 367 $approvedlist = new \core_privacy\local\request\approved_contextlist($user2, 'core_course', 368 [$systemcontext->id]); 369 \core_course\privacy\provider::delete_data_for_user($approvedlist); 370 371 // Ensure user2 and user3 are still returned in the course context. 372 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 373 \core_course\privacy\provider::get_users_in_context($userlist); 374 $actual = $userlist->get_userids(); 375 $expected = [ 376 $user2->id, 377 $user3->id 378 ]; 379 sort($expected); 380 sort($actual); 381 $this->assertEquals($expected, $actual); 382 383 // Delete user2's data in the course context. 384 $approvedlist = new \core_privacy\local\request\approved_contextlist($user2, 'core_course', 385 [$this->coursecontext->id]); 386 \core_course\privacy\provider::delete_data_for_user($approvedlist); 387 388 // Ensure user2's is deleted and user3 is still returned in the course context. 389 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 390 \core_course\privacy\provider::get_users_in_context($userlist); 391 $actual = $userlist->get_userids(); 392 $expected = [ 393 $user3->id 394 ]; 395 $this->assertEquals($expected, $actual); 396 } 397 398 /** 399 * Test deleting data within a context for an approved userlist. 400 */ 401 public function test_delete_data_for_users() { 402 $this->resetAfterTest(); 403 404 $component = 'core_course'; 405 $user1 = $this->getDataGenerator()->create_user(); 406 $user2 = $this->getDataGenerator()->create_user(); 407 $user3 = $this->getDataGenerator()->create_user(); 408 409 $this->create_course_completion(); 410 $this->complete_course($user1); 411 $this->complete_course($user2); 412 413 // Ensure user1, user2 are returned in the course context. 414 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 415 \core_course\privacy\provider::get_users_in_context($userlist); 416 $actual = $userlist->get_userids(); 417 $expected = [ 418 $user1->id, 419 $user2->id 420 ]; 421 sort($expected); 422 sort($actual); 423 $this->assertCount(2, $actual); 424 $this->assertEquals($expected, $actual); 425 426 $systemcontext = \context_system::instance(); 427 // User3 has a favourite course. 428 $user3ctx = \context_user::instance($user3->id); 429 $ufservice = \core_favourites\service_factory::get_service_for_user_context($user3ctx); 430 $ufservice->create_favourite('core_course', 'courses', $this->coursecontext->instanceid, 431 $this->coursecontext); 432 433 // Ensure user1, user2 and user3 are now returned in the course context. 434 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 435 \core_course\privacy\provider::get_users_in_context($userlist); 436 $actual = $userlist->get_userids(); 437 $expected = [ 438 $user1->id, 439 $user2->id, 440 $user3->id 441 ]; 442 sort($expected); 443 sort($actual); 444 $this->assertCount(3, $actual); 445 $this->assertEquals($expected, $actual); 446 447 // Delete data for user1 and user3 in the course context. 448 $approveduserids = [$user1->id, $user3->id]; 449 $approvedlist = new \core_privacy\local\request\approved_userlist($this->coursecontext, $component, $approveduserids); 450 \core_course\privacy\provider::delete_data_for_users($approvedlist); 451 452 // Ensure user1 and user3 are deleted and user2 is still returned in the course context. 453 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 454 \core_course\privacy\provider::get_users_in_context($userlist); 455 $actual = $userlist->get_userids(); 456 $expected = [$user2->id]; 457 $this->assertCount(1, $actual); 458 $this->assertEquals($expected, $actual); 459 460 // Try to delete user2's data in a context different than course (system context). 461 $approveduserids = [$user2->id]; 462 $approvedlist = new \core_privacy\local\request\approved_userlist($systemcontext, $component, $approveduserids); 463 \core_course\privacy\provider::delete_data_for_users($approvedlist); 464 465 // Ensure user2 is still returned in the course context. 466 $userlist = new \core_privacy\local\request\userlist($this->coursecontext, 'core_course'); 467 \core_course\privacy\provider::get_users_in_context($userlist); 468 $actual = $userlist->get_userids(); 469 $expected = [ 470 $user2->id 471 ]; 472 $this->assertCount(1, $actual); 473 $this->assertEquals($expected, $actual); 474 } 475 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body