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