Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace core_user; 18 19 defined('MOODLE_INTERNAL') || die(); 20 21 global $CFG; 22 require_once($CFG->dirroot.'/user/lib.php'); 23 24 /** 25 * Unit tests for user lib api. 26 * 27 * @package core_user 28 * @category test 29 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com> 30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 */ 32 class userlib_test extends \advanced_testcase { 33 /** 34 * Test user_get_user_details_courses 35 */ 36 public function test_user_get_user_details_courses() { 37 global $DB; 38 39 $this->resetAfterTest(); 40 41 // Create user and modify user profile. 42 $user1 = $this->getDataGenerator()->create_user(); 43 $user2 = $this->getDataGenerator()->create_user(); 44 $user3 = $this->getDataGenerator()->create_user(); 45 46 $course1 = $this->getDataGenerator()->create_course(); 47 $coursecontext = \context_course::instance($course1->id); 48 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 49 $this->getDataGenerator()->enrol_user($user1->id, $course1->id); 50 $this->getDataGenerator()->enrol_user($user2->id, $course1->id); 51 role_assign($teacherrole->id, $user1->id, $coursecontext->id); 52 role_assign($teacherrole->id, $user2->id, $coursecontext->id); 53 54 accesslib_clear_all_caches_for_unit_testing(); 55 56 // Get user2 details as a user with super system capabilities. 57 $result = user_get_user_details_courses($user2); 58 $this->assertEquals($user2->id, $result['id']); 59 $this->assertEquals(fullname($user2), $result['fullname']); 60 $this->assertEquals($course1->id, $result['enrolledcourses'][0]['id']); 61 62 $this->setUser($user1); 63 // Get user2 details as a user who can only see this user in a course. 64 $result = user_get_user_details_courses($user2); 65 $this->assertEquals($user2->id, $result['id']); 66 $this->assertEquals(fullname($user2), $result['fullname']); 67 $this->assertEquals($course1->id, $result['enrolledcourses'][0]['id']); 68 69 // Get user2 details as a user who doesn't share any course with user2. 70 $this->setUser($user3); 71 $result = user_get_user_details_courses($user2); 72 $this->assertNull($result); 73 } 74 75 /** 76 * Verify return when course groupmode set to 'no groups'. 77 */ 78 public function test_user_get_user_details_courses_groupmode_nogroups() { 79 $this->resetAfterTest(); 80 81 // Enrol 2 users into a course with groupmode set to 'no groups'. 82 // Profiles should be visible. 83 $user1 = $this->getDataGenerator()->create_user(); 84 $user2 = $this->getDataGenerator()->create_user(); 85 $course = $this->getDataGenerator()->create_course((object) ['groupmode' => 0]); 86 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 87 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 88 89 $this->setUser($user1); 90 $userdetails = user_get_user_details_courses($user2); 91 $this->assertIsArray($userdetails); 92 $this->assertEquals($user2->id, $userdetails['id']); 93 } 94 95 /** 96 * Verify return when course groupmode set to 'separate groups'. 97 */ 98 public function test_user_get_user_details_courses_groupmode_separate() { 99 $this->resetAfterTest(); 100 101 // Enrol 2 users into a course with groupmode set to 'separate groups'. 102 // The users are not in any groups, so profiles should be hidden (same as if they were in separate groups). 103 $user1 = $this->getDataGenerator()->create_user(); 104 $user2 = $this->getDataGenerator()->create_user(); 105 $course = $this->getDataGenerator()->create_course((object) ['groupmode' => 1]); 106 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 107 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 108 109 $this->setUser($user1); 110 $this->assertNull(user_get_user_details_courses($user2)); 111 } 112 113 /** 114 * Verify return when course groupmode set to 'visible groups'. 115 */ 116 public function test_user_get_user_details_courses_groupmode_visible() { 117 $this->resetAfterTest(); 118 119 // Enrol 2 users into a course with groupmode set to 'visible groups'. 120 // The users are not in any groups, and profiles should be visible because of the groupmode. 121 $user1 = $this->getDataGenerator()->create_user(); 122 $user2 = $this->getDataGenerator()->create_user(); 123 $course = $this->getDataGenerator()->create_course((object) ['groupmode' => 2]); 124 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 125 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 126 127 $this->setUser($user1); 128 $userdetails = user_get_user_details_courses($user2); 129 $this->assertIsArray($userdetails); 130 $this->assertEquals($user2->id, $userdetails['id']); 131 } 132 133 /** 134 * Test user_update_user. 135 */ 136 public function test_user_update_user() { 137 global $DB; 138 139 $this->resetAfterTest(); 140 141 // Create user and modify user profile. 142 $user = $this->getDataGenerator()->create_user(); 143 $user->firstname = 'Test'; 144 $user->password = 'M00dLe@T'; 145 146 // Update user and capture event. 147 $sink = $this->redirectEvents(); 148 user_update_user($user); 149 $events = $sink->get_events(); 150 $sink->close(); 151 $event = array_pop($events); 152 153 // Test updated value. 154 $dbuser = $DB->get_record('user', array('id' => $user->id)); 155 $this->assertSame($user->firstname, $dbuser->firstname); 156 $this->assertNotSame('M00dLe@T', $dbuser->password); 157 158 // Test event. 159 $this->assertInstanceOf('\core\event\user_updated', $event); 160 $this->assertSame($user->id, $event->objectid); 161 $this->assertSame('user_updated', $event->get_legacy_eventname()); 162 $this->assertEventLegacyData($dbuser, $event); 163 $this->assertEquals(\context_user::instance($user->id), $event->get_context()); 164 $expectedlogdata = array(SITEID, 'user', 'update', 'view.php?id='.$user->id, ''); 165 $this->assertEventLegacyLogData($expectedlogdata, $event); 166 167 // Update user with no password update. 168 $password = $user->password = hash_internal_user_password('M00dLe@T'); 169 user_update_user($user, false); 170 $dbuser = $DB->get_record('user', array('id' => $user->id)); 171 $this->assertSame($password, $dbuser->password); 172 173 // Verify event is not triggred by user_update_user when needed. 174 $sink = $this->redirectEvents(); 175 user_update_user($user, false, false); 176 $events = $sink->get_events(); 177 $sink->close(); 178 $this->assertCount(0, $events); 179 180 // With password, there should be 1 event. 181 $sink = $this->redirectEvents(); 182 user_update_user($user, true, false); 183 $events = $sink->get_events(); 184 $sink->close(); 185 $this->assertCount(1, $events); 186 $event = array_pop($events); 187 $this->assertInstanceOf('\core\event\user_password_updated', $event); 188 189 // Test user data validation. 190 $user->username = 'johndoe123'; 191 $user->auth = 'shibolth'; 192 $user->country = 'WW'; 193 $user->lang = 'xy'; 194 $user->theme = 'somewrongthemename'; 195 $user->timezone = '30.5'; 196 $debugmessages = $this->getDebuggingMessages(); 197 user_update_user($user, true, false); 198 $this->assertDebuggingCalledCount(5, $debugmessages); 199 200 // Now, with valid user data. 201 $user->username = 'johndoe321'; 202 $user->auth = 'shibboleth'; 203 $user->country = 'AU'; 204 $user->lang = 'en'; 205 $user->theme = 'classic'; 206 $user->timezone = 'Australia/Perth'; 207 user_update_user($user, true, false); 208 $this->assertDebuggingNotCalled(); 209 } 210 211 /** 212 * Test create_users. 213 */ 214 public function test_create_users() { 215 global $DB; 216 217 $this->resetAfterTest(); 218 219 $user = array( 220 'username' => 'usernametest1', 221 'password' => 'Moodle2012!', 222 'idnumber' => 'idnumbertest1', 223 'firstname' => 'First Name User Test 1', 224 'lastname' => 'Last Name User Test 1', 225 'middlename' => 'Middle Name User Test 1', 226 'lastnamephonetic' => '最後のお名前のテスト一号', 227 'firstnamephonetic' => 'お名前のテスト一号', 228 'alternatename' => 'Alternate Name User Test 1', 229 'email' => 'usertest1@example.com', 230 'description' => 'This is a description for user 1', 231 'city' => 'Perth', 232 'country' => 'AU' 233 ); 234 235 // Create user and capture event. 236 $sink = $this->redirectEvents(); 237 $user['id'] = user_create_user($user); 238 $events = $sink->get_events(); 239 $sink->close(); 240 $event = array_pop($events); 241 242 // Test user info in DB. 243 $dbuser = $DB->get_record('user', array('id' => $user['id'])); 244 $this->assertEquals($dbuser->username, $user['username']); 245 $this->assertEquals($dbuser->idnumber, $user['idnumber']); 246 $this->assertEquals($dbuser->firstname, $user['firstname']); 247 $this->assertEquals($dbuser->lastname, $user['lastname']); 248 $this->assertEquals($dbuser->email, $user['email']); 249 $this->assertEquals($dbuser->description, $user['description']); 250 $this->assertEquals($dbuser->city, $user['city']); 251 $this->assertEquals($dbuser->country, $user['country']); 252 253 // Test event. 254 $this->assertInstanceOf('\core\event\user_created', $event); 255 $this->assertEquals($user['id'], $event->objectid); 256 $this->assertEquals('user_created', $event->get_legacy_eventname()); 257 $this->assertEquals(\context_user::instance($user['id']), $event->get_context()); 258 $this->assertEventLegacyData($dbuser, $event); 259 $expectedlogdata = array(SITEID, 'user', 'add', '/view.php?id='.$event->objectid, fullname($dbuser)); 260 $this->assertEventLegacyLogData($expectedlogdata, $event); 261 262 // Verify event is not triggred by user_create_user when needed. 263 $user = array('username' => 'usernametest2'); // Create another user. 264 $sink = $this->redirectEvents(); 265 user_create_user($user, true, false); 266 $events = $sink->get_events(); 267 $sink->close(); 268 $this->assertCount(0, $events); 269 270 // Test user data validation, first some invalid data. 271 $user['username'] = 'johndoe123'; 272 $user['auth'] = 'shibolth'; 273 $user['country'] = 'WW'; 274 $user['lang'] = 'xy'; 275 $user['theme'] = 'somewrongthemename'; 276 $user['timezone'] = '-30.5'; 277 $debugmessages = $this->getDebuggingMessages(); 278 $user['id'] = user_create_user($user, true, false); 279 $this->assertDebuggingCalledCount(5, $debugmessages); 280 $dbuser = $DB->get_record('user', array('id' => $user['id'])); 281 $this->assertEquals($dbuser->country, 0); 282 $this->assertEquals($dbuser->lang, 'en'); 283 $this->assertEquals($dbuser->timezone, ''); 284 285 // Now, with valid user data. 286 $user['username'] = 'johndoe321'; 287 $user['auth'] = 'shibboleth'; 288 $user['country'] = 'AU'; 289 $user['lang'] = 'en'; 290 $user['theme'] = 'classic'; 291 $user['timezone'] = 'Australia/Perth'; 292 user_create_user($user, true, false); 293 $this->assertDebuggingNotCalled(); 294 } 295 296 /** 297 * Test that creating users populates default values 298 * 299 * @covers ::user_create_user 300 */ 301 public function test_user_create_user_default_values(): void { 302 global $CFG; 303 304 $this->resetAfterTest(); 305 306 // Update default values for city/country (both initially empty). 307 set_config('defaultcity', 'Nadi'); 308 set_config('country', 'FJ'); 309 310 $userid = user_create_user((object) [ 311 'username' => 'newuser', 312 ], false, false); 313 314 $user = \core_user::get_user($userid); 315 $this->assertEquals($CFG->calendartype, $user->calendartype); 316 $this->assertEquals($CFG->defaultpreference_maildisplay, $user->maildisplay); 317 $this->assertEquals($CFG->defaultpreference_mailformat, $user->mailformat); 318 $this->assertEquals($CFG->defaultpreference_maildigest, $user->maildigest); 319 $this->assertEquals($CFG->defaultpreference_autosubscribe, $user->autosubscribe); 320 $this->assertEquals($CFG->defaultpreference_trackforums, $user->trackforums); 321 $this->assertEquals($CFG->lang, $user->lang); 322 $this->assertEquals($CFG->defaultcity, $user->city); 323 $this->assertEquals($CFG->country, $user->country); 324 } 325 326 /** 327 * Test that {@link user_create_user()} throws exception when invalid username is provided. 328 * 329 * @dataProvider data_create_user_invalid_username 330 * @param string $username Invalid username 331 * @param string $expectmessage Expected exception message 332 */ 333 public function test_create_user_invalid_username($username, $expectmessage) { 334 global $CFG; 335 336 $this->resetAfterTest(); 337 $CFG->extendedusernamechars = false; 338 339 $user = [ 340 'username' => $username, 341 ]; 342 343 $this->expectException('moodle_exception'); 344 $this->expectExceptionMessage($expectmessage); 345 346 user_create_user($user); 347 } 348 349 /** 350 * Data provider for {@link self::test_create_user_invalid_username()}. 351 * 352 * @return array 353 */ 354 public function data_create_user_invalid_username() { 355 return [ 356 'empty_string' => [ 357 '', 358 'The username cannot be blank', 359 ], 360 'only_whitespace' => [ 361 "\t\t \t\n ", 362 'The username cannot be blank', 363 ], 364 'lower_case' => [ 365 'Mudrd8mz', 366 'The username must be in lower case', 367 ], 368 'extended_chars' => [ 369 'dmudrák', 370 'The given username contains invalid characters', 371 ], 372 ]; 373 } 374 375 /** 376 * Test function user_count_login_failures(). 377 */ 378 public function test_user_count_login_failures() { 379 $this->resetAfterTest(); 380 $user = $this->getDataGenerator()->create_user(); 381 $this->assertEquals(0, get_user_preferences('login_failed_count_since_success', 0, $user)); 382 for ($i = 0; $i < 10; $i++) { 383 login_attempt_failed($user); 384 } 385 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user)); 386 $count = user_count_login_failures($user); // Reset count. 387 $this->assertEquals(10, $count); 388 $this->assertEquals(0, get_user_preferences('login_failed_count_since_success', 0, $user)); 389 390 for ($i = 0; $i < 10; $i++) { 391 login_attempt_failed($user); 392 } 393 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user)); 394 $count = user_count_login_failures($user, false); // Do not reset count. 395 $this->assertEquals(10, $count); 396 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user)); 397 } 398 399 /** 400 * Test function user_add_password_history(). 401 */ 402 public function test_user_add_password_history() { 403 global $DB; 404 405 $this->resetAfterTest(); 406 407 $user1 = $this->getDataGenerator()->create_user(); 408 $user2 = $this->getDataGenerator()->create_user(); 409 $user3 = $this->getDataGenerator()->create_user(); 410 $DB->delete_records('user_password_history', array()); 411 412 set_config('passwordreuselimit', 0); 413 414 user_add_password_history($user1->id, 'pokus'); 415 $this->assertEquals(0, $DB->count_records('user_password_history')); 416 417 // Test adding and discarding of old. 418 419 set_config('passwordreuselimit', 3); 420 421 user_add_password_history($user1->id, 'pokus'); 422 $this->assertEquals(1, $DB->count_records('user_password_history')); 423 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id))); 424 425 user_add_password_history($user1->id, 'pokus2'); 426 user_add_password_history($user1->id, 'pokus3'); 427 user_add_password_history($user1->id, 'pokus4'); 428 $this->assertEquals(3, $DB->count_records('user_password_history')); 429 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user1->id))); 430 431 user_add_password_history($user2->id, 'pokus1'); 432 $this->assertEquals(4, $DB->count_records('user_password_history')); 433 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user1->id))); 434 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user2->id))); 435 436 user_add_password_history($user2->id, 'pokus2'); 437 user_add_password_history($user2->id, 'pokus3'); 438 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user2->id))); 439 440 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC')); 441 user_add_password_history($user2->id, 'pokus4'); 442 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user2->id))); 443 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC')); 444 445 $removed = array_shift($ids); 446 $added = array_pop($newids); 447 $this->assertSame($ids, $newids); 448 $this->assertGreaterThan($removed, $added); 449 450 // Test disabling prevents changes. 451 452 set_config('passwordreuselimit', 0); 453 454 $this->assertEquals(6, $DB->count_records('user_password_history')); 455 456 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC')); 457 user_add_password_history($user2->id, 'pokus5'); 458 user_add_password_history($user3->id, 'pokus1'); 459 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC')); 460 $this->assertSame($ids, $newids); 461 $this->assertEquals(6, $DB->count_records('user_password_history')); 462 463 set_config('passwordreuselimit', -1); 464 465 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC')); 466 user_add_password_history($user2->id, 'pokus6'); 467 user_add_password_history($user3->id, 'pokus6'); 468 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id), 'timecreated ASC, id ASC')); 469 $this->assertSame($ids, $newids); 470 $this->assertEquals(6, $DB->count_records('user_password_history')); 471 } 472 473 /** 474 * Test function user_add_password_history(). 475 */ 476 public function test_user_is_previously_used_password() { 477 global $DB; 478 479 $this->resetAfterTest(); 480 481 $user1 = $this->getDataGenerator()->create_user(); 482 $user2 = $this->getDataGenerator()->create_user(); 483 $DB->delete_records('user_password_history', array()); 484 485 set_config('passwordreuselimit', 0); 486 487 user_add_password_history($user1->id, 'pokus'); 488 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus')); 489 490 set_config('passwordreuselimit', 3); 491 492 user_add_password_history($user2->id, 'pokus1'); 493 user_add_password_history($user2->id, 'pokus2'); 494 495 user_add_password_history($user1->id, 'pokus1'); 496 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus1')); 497 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2')); 498 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus3')); 499 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4')); 500 501 user_add_password_history($user1->id, 'pokus2'); 502 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus1')); 503 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus2')); 504 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus3')); 505 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4')); 506 507 user_add_password_history($user1->id, 'pokus3'); 508 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus1')); 509 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus2')); 510 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3')); 511 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4')); 512 513 user_add_password_history($user1->id, 'pokus4'); 514 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1')); 515 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus2')); 516 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3')); 517 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus4')); 518 519 set_config('passwordreuselimit', 2); 520 521 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1')); 522 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2')); 523 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3')); 524 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus4')); 525 526 set_config('passwordreuselimit', 3); 527 528 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1')); 529 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2')); 530 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus3')); 531 $this->assertTrue(user_is_previously_used_password($user1->id, 'pokus4')); 532 533 set_config('passwordreuselimit', 0); 534 535 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus1')); 536 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus2')); 537 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus3')); 538 $this->assertFalse(user_is_previously_used_password($user1->id, 'pokus4')); 539 } 540 541 /** 542 * Test that password history is deleted together with user. 543 */ 544 public function test_delete_of_hashes_on_user_delete() { 545 global $DB; 546 547 $this->resetAfterTest(); 548 549 $user1 = $this->getDataGenerator()->create_user(); 550 $user2 = $this->getDataGenerator()->create_user(); 551 $DB->delete_records('user_password_history', array()); 552 553 set_config('passwordreuselimit', 3); 554 555 user_add_password_history($user1->id, 'pokus'); 556 user_add_password_history($user2->id, 'pokus1'); 557 user_add_password_history($user2->id, 'pokus2'); 558 559 $this->assertEquals(3, $DB->count_records('user_password_history')); 560 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id))); 561 $this->assertEquals(2, $DB->count_records('user_password_history', array('userid' => $user2->id))); 562 563 delete_user($user2); 564 $this->assertEquals(1, $DB->count_records('user_password_history')); 565 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id))); 566 $this->assertEquals(0, $DB->count_records('user_password_history', array('userid' => $user2->id))); 567 } 568 569 /** 570 * Test user_list_view function 571 */ 572 public function test_user_list_view() { 573 574 $this->resetAfterTest(); 575 576 // Course without sections. 577 $course = $this->getDataGenerator()->create_course(); 578 $context = \context_course::instance($course->id); 579 580 $this->setAdminUser(); 581 582 // Redirect events to the sink, so we can recover them later. 583 $sink = $this->redirectEvents(); 584 585 user_list_view($course, $context); 586 $events = $sink->get_events(); 587 $this->assertCount(1, $events); 588 $event = reset($events); 589 590 // Check the event details are correct. 591 $this->assertInstanceOf('\core\event\user_list_viewed', $event); 592 $this->assertEquals($context, $event->get_context()); 593 $this->assertEquals($course->shortname, $event->other['courseshortname']); 594 $this->assertEquals($course->fullname, $event->other['coursefullname']); 595 596 } 597 598 /** 599 * Test setting the user menu avatar size. 600 */ 601 public function test_user_menu_custom_avatar_size() { 602 global $PAGE; 603 $this->resetAfterTest(true); 604 605 $testsize = 100; 606 607 $PAGE->set_url('/'); 608 $user = $this->getDataGenerator()->create_user(); 609 $this->setUser($user); 610 $opts = user_get_user_navigation_info($user, $PAGE, array('avatarsize' => $testsize)); 611 $avatarhtml = $opts->metadata['useravatar']; 612 613 $matches = []; 614 preg_match('/size-100/', $avatarhtml, $matches); 615 $this->assertCount(1, $matches); 616 } 617 618 /** 619 * Test user_can_view_profile 620 */ 621 public function test_user_can_view_profile() { 622 global $DB, $CFG; 623 624 $this->resetAfterTest(); 625 626 // Create five users. 627 $user1 = $this->getDataGenerator()->create_user(); 628 $user2 = $this->getDataGenerator()->create_user(); 629 $user3 = $this->getDataGenerator()->create_user(); 630 $user4 = $this->getDataGenerator()->create_user(); 631 $user5 = $this->getDataGenerator()->create_user(); 632 $user6 = $this->getDataGenerator()->create_user(array('deleted' => 1)); 633 $user7 = $this->getDataGenerator()->create_user(); 634 $user8 = $this->getDataGenerator()->create_user(); 635 $user8->id = 0; // Visitor. 636 637 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 638 // Add the course creator role to the course contact and assign a user to that role. 639 $CFG->coursecontact = '2'; 640 $coursecreatorrole = $DB->get_record('role', array('shortname' => 'coursecreator')); 641 $this->getDataGenerator()->role_assign($coursecreatorrole->id, $user7->id); 642 643 // Create two courses. 644 $course1 = $this->getDataGenerator()->create_course(); 645 $course2 = $this->getDataGenerator()->create_course(); 646 $coursecontext = \context_course::instance($course2->id); 647 // Prepare another course with separate groups and groupmodeforce set to true. 648 $record = new \stdClass(); 649 $record->groupmode = 1; 650 $record->groupmodeforce = 1; 651 $course3 = $this->getDataGenerator()->create_course($record); 652 // Enrol users 1 and 2 in first course. 653 $this->getDataGenerator()->enrol_user($user1->id, $course1->id); 654 $this->getDataGenerator()->enrol_user($user2->id, $course1->id); 655 // Enrol users 2 and 3 in second course. 656 $this->getDataGenerator()->enrol_user($user2->id, $course2->id); 657 $this->getDataGenerator()->enrol_user($user3->id, $course2->id); 658 // Enrol users 1, 4, and 5 into course 3. 659 $this->getDataGenerator()->enrol_user($user1->id, $course3->id); 660 $this->getDataGenerator()->enrol_user($user4->id, $course3->id); 661 $this->getDataGenerator()->enrol_user($user5->id, $course3->id); 662 663 // User 3 should not be able to see user 1, either by passing their own course (course 2) or user 1's course (course 1). 664 $this->setUser($user3); 665 $this->assertFalse(user_can_view_profile($user1, $course2)); 666 $this->assertFalse(user_can_view_profile($user1, $course1)); 667 668 // Remove capability moodle/user:viewdetails in course 2. 669 assign_capability('moodle/user:viewdetails', CAP_PROHIBIT, $studentrole->id, $coursecontext); 670 // Set current user to user 1. 671 $this->setUser($user1); 672 // User 1 can see User 1's profile. 673 $this->assertTrue(user_can_view_profile($user1)); 674 675 $tempcfg = $CFG->forceloginforprofiles; 676 $CFG->forceloginforprofiles = 0; 677 // Not forced to log in to view profiles, should be able to see all profiles besides user 6. 678 $users = array($user1, $user2, $user3, $user4, $user5, $user7); 679 foreach ($users as $user) { 680 $this->assertTrue(user_can_view_profile($user)); 681 } 682 // Restore setting. 683 $CFG->forceloginforprofiles = $tempcfg; 684 685 // User 1 can not see user 6 as they have been deleted. 686 $this->assertFalse(user_can_view_profile($user6)); 687 // User 1 can see User 7 as they are a course contact. 688 $this->assertTrue(user_can_view_profile($user7)); 689 // User 1 is in a course with user 2 and has the right capability - return true. 690 $this->assertTrue(user_can_view_profile($user2)); 691 // User 1 is not in a course with user 3 - return false. 692 $this->assertFalse(user_can_view_profile($user3)); 693 694 // Set current user to user 2. 695 $this->setUser($user2); 696 // User 2 is in a course with user 3 but does not have the right capability - return false. 697 $this->assertFalse(user_can_view_profile($user3)); 698 699 // Set user 1 in one group and users 4 and 5 in another group. 700 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course3->id)); 701 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course3->id)); 702 groups_add_member($group1->id, $user1->id); 703 groups_add_member($group2->id, $user4->id); 704 groups_add_member($group2->id, $user5->id); 705 $this->setUser($user1); 706 // Check that user 1 can not see user 4. 707 $this->assertFalse(user_can_view_profile($user4)); 708 // Check that user 5 can see user 4. 709 $this->setUser($user5); 710 $this->assertTrue(user_can_view_profile($user4)); 711 712 // Test the user:viewalldetails cap check using the course creator role which, by default, can't see student profiles. 713 $this->setUser($user7); 714 $this->assertFalse(user_can_view_profile($user4)); 715 assign_capability('moodle/user:viewalldetails', CAP_ALLOW, $coursecreatorrole->id, \context_system::instance()->id, true); 716 reload_all_capabilities(); 717 $this->assertTrue(user_can_view_profile($user4)); 718 unassign_capability('moodle/user:viewalldetails', $coursecreatorrole->id, $coursecontext->id); 719 reload_all_capabilities(); 720 721 $CFG->coursecontact = null; 722 723 // Visitor (Not a guest user, userid=0). 724 $CFG->forceloginforprofiles = 1; 725 $this->setUser($user8); 726 $this->assertFalse(user_can_view_profile($user1)); 727 728 // Let us test with guest user. 729 $this->setGuestUser(); 730 $CFG->forceloginforprofiles = 1; 731 foreach ($users as $user) { 732 $this->assertFalse(user_can_view_profile($user)); 733 } 734 735 // Even with cap, still guests should not be allowed in. 736 $guestrole = $DB->get_records_menu('role', array('shortname' => 'guest'), 'id', 'archetype, id'); 737 assign_capability('moodle/user:viewdetails', CAP_ALLOW, $guestrole['guest'], \context_system::instance()->id, true); 738 reload_all_capabilities(); 739 foreach ($users as $user) { 740 $this->assertFalse(user_can_view_profile($user)); 741 } 742 743 $CFG->forceloginforprofiles = 0; 744 foreach ($users as $user) { 745 $this->assertTrue(user_can_view_profile($user)); 746 } 747 748 // Let us test with Visitor user. 749 $this->setUser($user8); 750 $CFG->forceloginforprofiles = 1; 751 foreach ($users as $user) { 752 $this->assertFalse(user_can_view_profile($user)); 753 } 754 755 $CFG->forceloginforprofiles = 0; 756 foreach ($users as $user) { 757 $this->assertTrue(user_can_view_profile($user)); 758 } 759 760 // Testing non-shared courses where capabilities are met, using system role overrides. 761 $CFG->forceloginforprofiles = $tempcfg; 762 $course4 = $this->getDataGenerator()->create_course(); 763 $this->getDataGenerator()->enrol_user($user1->id, $course4->id); 764 765 // Assign a manager role at the system context. 766 $managerrole = $DB->get_record('role', array('shortname' => 'manager')); 767 $user9 = $this->getDataGenerator()->create_user(); 768 $this->getDataGenerator()->role_assign($managerrole->id, $user9->id); 769 770 // Make sure viewalldetails and viewdetails are overridden to 'prevent' (i.e. can be overridden at a lower context). 771 $systemcontext = \context_system::instance(); 772 assign_capability('moodle/user:viewdetails', CAP_PREVENT, $managerrole->id, $systemcontext, true); 773 assign_capability('moodle/user:viewalldetails', CAP_PREVENT, $managerrole->id, $systemcontext, true); 774 775 // And override these to 'Allow' in a specific course. 776 $course4context = \context_course::instance($course4->id); 777 assign_capability('moodle/user:viewalldetails', CAP_ALLOW, $managerrole->id, $course4context, true); 778 assign_capability('moodle/user:viewdetails', CAP_ALLOW, $managerrole->id, $course4context, true); 779 780 // The manager now shouldn't have viewdetails in the system or user context. 781 $this->setUser($user9); 782 $user1context = \context_user::instance($user1->id); 783 $this->assertFalse(has_capability('moodle/user:viewdetails', $systemcontext)); 784 $this->assertFalse(has_capability('moodle/user:viewdetails', $user1context)); 785 786 // Confirm that user_can_view_profile() returns true for $user1 when called without $course param. It should find $course1. 787 $this->assertTrue(user_can_view_profile($user1)); 788 789 // Confirm this also works when restricting scope to just that course. 790 $this->assertTrue(user_can_view_profile($user1, $course4)); 791 } 792 793 /** 794 * Test user_get_user_details 795 */ 796 public function test_user_get_user_details() { 797 global $DB; 798 799 $this->resetAfterTest(); 800 801 // Create user and modify user profile. 802 $teacher = $this->getDataGenerator()->create_user(); 803 $student = $this->getDataGenerator()->create_user(); 804 $studentfullname = fullname($student); 805 806 $course1 = $this->getDataGenerator()->create_course(); 807 $coursecontext = \context_course::instance($course1->id); 808 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 809 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 810 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id); 811 $this->getDataGenerator()->enrol_user($student->id, $course1->id); 812 role_assign($teacherrole->id, $teacher->id, $coursecontext->id); 813 role_assign($studentrole->id, $student->id, $coursecontext->id); 814 815 accesslib_clear_all_caches_for_unit_testing(); 816 817 // Get student details as a user with super system capabilities. 818 $result = user_get_user_details($student, $course1); 819 $this->assertEquals($student->id, $result['id']); 820 $this->assertEquals($studentfullname, $result['fullname']); 821 $this->assertEquals($course1->id, $result['enrolledcourses'][0]['id']); 822 823 $this->setUser($teacher); 824 // Get student details as a user who can only see this user in a course. 825 $result = user_get_user_details($student, $course1); 826 $this->assertEquals($student->id, $result['id']); 827 $this->assertEquals($studentfullname, $result['fullname']); 828 $this->assertEquals($course1->id, $result['enrolledcourses'][0]['id']); 829 830 // Get student details with required fields. 831 $result = user_get_user_details($student, $course1, array('id', 'fullname')); 832 $this->assertCount(2, $result); 833 $this->assertEquals($student->id, $result['id']); 834 $this->assertEquals($studentfullname, $result['fullname']); 835 836 // Get exception for invalid required fields. 837 $this->expectException('moodle_exception'); 838 $result = user_get_user_details($student, $course1, array('wrongrequiredfield')); 839 } 840 841 /** 842 * Regression test for MDL-57840. 843 * 844 * Ensure the fields "auth, confirmed, idnumber, lang, theme, timezone and mailformat" are present when 845 * calling user_get_user_details() function. 846 */ 847 public function test_user_get_user_details_missing_fields() { 848 global $CFG; 849 850 $this->resetAfterTest(true); 851 $this->setAdminUser(); // We need capabilities to view the data. 852 $user = self::getDataGenerator()->create_user([ 853 'auth' => 'email', 854 'confirmed' => '0', 855 'idnumber' => 'someidnumber', 856 'lang' => 'en', 857 'theme' => $CFG->theme, 858 'timezone' => '5', 859 'mailformat' => '0', 860 ]); 861 862 // Fields that should get by default. 863 $got = user_get_user_details($user); 864 self::assertSame('email', $got['auth']); 865 self::assertSame('0', $got['confirmed']); 866 self::assertSame('someidnumber', $got['idnumber']); 867 self::assertSame('en', $got['lang']); 868 self::assertSame($CFG->theme, $got['theme']); 869 self::assertSame('5', $got['timezone']); 870 self::assertSame('0', $got['mailformat']); 871 } 872 873 /** 874 * Test user_get_user_details_permissions 875 * @covers ::user_get_user_details 876 */ 877 public function test_user_get_user_details_permissions() { 878 global $CFG, $DB; 879 880 $this->resetAfterTest(); 881 882 // Create user and modify user profile. 883 $teacher = $this->getDataGenerator()->create_user(); 884 $student1 = $this->getDataGenerator()->create_user(['idnumber' => 'user1id', 'city' => 'Barcelona', 'address' => 'BCN 1B']); 885 $student2 = $this->getDataGenerator()->create_user(); 886 $student1fullname = fullname($student1); 887 888 $course = $this->getDataGenerator()->create_course(); 889 $coursecontext = \context_course::instance($course->id); 890 $this->getDataGenerator()->enrol_user($teacher->id, $course->id); 891 $this->getDataGenerator()->enrol_user($student1->id, $course->id); 892 $this->getDataGenerator()->enrol_user($student2->id, $course->id); 893 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 894 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 895 $this->getDataGenerator()->role_assign($teacherrole->id, $teacher->id, $coursecontext->id); 896 $this->getDataGenerator()->role_assign($studentrole->id, $student1->id, $coursecontext->id); 897 $this->getDataGenerator()->role_assign($studentrole->id, $student2->id, $coursecontext->id); 898 899 accesslib_clear_all_caches_for_unit_testing(); 900 901 // Get student details as a user with super system capabilities. 902 $result = user_get_user_details($student1, $course); 903 $this->assertEquals($student1->id, $result['id']); 904 $this->assertEquals($student1fullname, $result['fullname']); 905 $this->assertEquals($course->id, $result['enrolledcourses'][0]['id']); 906 907 $this->setUser($student2); 908 909 // Get student details with required fields. 910 $result = user_get_user_details($student1, $course, array('id', 'fullname', 'timezone', 'city', 'address', 'idnumber')); 911 $this->assertCount(4, $result); // Ensure address (never returned), idnumber (identity field) are not returned here. 912 $this->assertEquals($student1->id, $result['id']); 913 $this->assertEquals($student1fullname, $result['fullname']); 914 $this->assertEquals($student1->timezone, $result['timezone']); 915 $this->assertEquals($student1->city, $result['city']); 916 917 // Set new identity fields and hidden fields and try to retrieve them without permission. 918 $CFG->showuseridentity = $CFG->showuseridentity . ',idnumber'; 919 $CFG->hiddenuserfields = 'city'; 920 $result = user_get_user_details($student1, $course, array('id', 'fullname', 'timezone', 'city', 'address', 'idnumber')); 921 $this->assertCount(3, $result); // Ensure address, city and idnumber are not returned here. 922 $this->assertEquals($student1->id, $result['id']); 923 $this->assertEquals($student1fullname, $result['fullname']); 924 $this->assertEquals($student1->timezone, $result['timezone']); 925 926 // Now, teacher should have permission to see the idnumber and city fields. 927 $this->setUser($teacher); 928 $result = user_get_user_details($student1, $course, array('id', 'fullname', 'timezone', 'city', 'address', 'idnumber')); 929 $this->assertCount(5, $result); // Ensure address is not returned here. 930 $this->assertEquals($student1->id, $result['id']); 931 $this->assertEquals($student1fullname, $result['fullname']); 932 $this->assertEquals($student1->timezone, $result['timezone']); 933 $this->assertEquals($student1->idnumber, $result['idnumber']); 934 $this->assertEquals($student1->city, $result['city']); 935 936 // And admins can see anything. 937 $this->setAdminUser(); 938 $result = user_get_user_details($student1, $course, array('id', 'fullname', 'timezone', 'city', 'address', 'idnumber')); 939 $this->assertCount(6, $result); 940 $this->assertEquals($student1->id, $result['id']); 941 $this->assertEquals($student1fullname, $result['fullname']); 942 $this->assertEquals($student1->timezone, $result['timezone']); 943 $this->assertEquals($student1->idnumber, $result['idnumber']); 944 $this->assertEquals($student1->city, $result['city']); 945 $this->assertEquals($student1->address, $result['address']); 946 } 947 948 /** 949 * Test user_get_user_details_groups. 950 * @covers ::user_get_user_details 951 */ 952 public function test_user_get_user_details_groups() { 953 global $DB; 954 $this->resetAfterTest(); 955 956 // Create user and modify user profile. 957 $teacher = $this->getDataGenerator()->create_user(); 958 $student1 = $this->getDataGenerator()->create_user(['idnumber' => 'user1id', 'city' => 'Barcelona', 'address' => 'BCN 1B']); 959 $student2 = $this->getDataGenerator()->create_user(); 960 961 $course = $this->getDataGenerator()->create_course(); 962 $coursecontext = \context_course::instance($course->id); 963 $this->getDataGenerator()->enrol_user($teacher->id, $course->id); 964 $this->getDataGenerator()->enrol_user($student1->id, $course->id); 965 $this->getDataGenerator()->enrol_user($student2->id, $course->id); 966 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); 967 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 968 $this->getDataGenerator()->role_assign($teacherrole->id, $teacher->id, $coursecontext->id); 969 $this->getDataGenerator()->role_assign($studentrole->id, $student1->id, $coursecontext->id); 970 $this->getDataGenerator()->role_assign($studentrole->id, $student2->id, $coursecontext->id); 971 972 $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'G1']); 973 $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'G2']); 974 975 // Each student in one group but teacher in two. 976 groups_add_member($group1->id, $student1->id); 977 groups_add_member($group1->id, $teacher->id); 978 groups_add_member($group2->id, $student2->id); 979 groups_add_member($group2->id, $teacher->id); 980 981 accesslib_clear_all_caches_for_unit_testing(); 982 983 // A student can see other users groups when separate groups are not forced. 984 $this->setUser($student2); 985 986 // Get student details with groups. 987 $result = user_get_user_details($student1, $course, array('id', 'fullname', 'groups')); 988 $this->assertCount(3, $result); 989 $this->assertEquals($group1->id, $result['groups'][0]['id']); 990 991 // Teacher is in two different groups. 992 $result = user_get_user_details($teacher, $course, array('id', 'fullname', 'groups')); 993 994 // Order by group id. 995 usort($result['groups'], function($a, $b) { 996 return $a['id'] - $b['id']; 997 }); 998 999 $this->assertCount(3, $result); 1000 $this->assertCount(2, $result['groups']); 1001 $this->assertEquals($group1->id, $result['groups'][0]['id']); 1002 $this->assertEquals($group2->id, $result['groups'][1]['id']); 1003 1004 // Change to separate groups. 1005 $course->groupmode = SEPARATEGROUPS; 1006 $course->groupmodeforce = true; 1007 update_course($course); 1008 1009 // Teacher is in two groups but I can only see the one shared with me. 1010 $result = user_get_user_details($teacher, $course, array('id', 'fullname', 'groups')); 1011 1012 $this->assertCount(3, $result); 1013 $this->assertCount(1, $result['groups']); 1014 $this->assertEquals($group2->id, $result['groups'][0]['id']); 1015 } 1016 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body