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