2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Unit tests for user/lib.php.
22 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') ||
die();
29 require_once($CFG->dirroot
.'/user/lib.php');
32 * Unit tests for user lib api.
36 * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 class core_userliblib_testcase
extends advanced_testcase
{
41 * Test user_get_user_details_courses
43 public function test_user_get_user_details_courses() {
46 $this->resetAfterTest();
48 // Create user and modify user profile.
49 $user1 = $this->getDataGenerator()->create_user();
50 $user2 = $this->getDataGenerator()->create_user();
51 $user3 = $this->getDataGenerator()->create_user();
53 $course1 = $this->getDataGenerator()->create_course();
54 $coursecontext = context_course
::instance($course1->id
);
55 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
56 $this->getDataGenerator()->enrol_user($user1->id
, $course1->id
);
57 $this->getDataGenerator()->enrol_user($user2->id
, $course1->id
);
58 role_assign($teacherrole->id
, $user1->id
, $coursecontext->id
);
59 role_assign($teacherrole->id
, $user2->id
, $coursecontext->id
);
61 accesslib_clear_all_caches_for_unit_testing();
63 // Get user2 details as a user with super system capabilities.
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']);
69 $this->setUser($user1);
70 // Get user2 details as a user who can only see this user in a course.
71 $result = user_get_user_details_courses($user2);
72 $this->assertEquals($user2->id
, $result['id']);
73 $this->assertEquals(fullname($user2), $result['fullname']);
74 $this->assertEquals($course1->id
, $result['enrolledcourses'][0]['id']);
76 // Get user2 details as a user who doesn't share any course with user2.
77 $this->setUser($user3);
78 $result = user_get_user_details_courses($user2);
79 $this->assertNull($result);
83 * Verify return when course groupmode set to 'no groups'.
85 public function test_user_get_user_details_courses_groupmode_nogroups() {
86 $this->resetAfterTest();
88 // Enrol 2 users into a course with groupmode set to 'no groups'.
89 // Profiles should be visible.
90 $user1 = $this->getDataGenerator()->create_user();
91 $user2 = $this->getDataGenerator()->create_user();
92 $course = $this->getDataGenerator()->create_course((object) ['groupmode' => 0]);
93 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
);
94 $this->getDataGenerator()->enrol_user($user2->id
, $course->id
);
96 $this->setUser($user1);
97 $userdetails = user_get_user_details_courses($user2);
98 $this->assertIsArray($userdetails);
99 $this->assertEquals($user2->id
, $userdetails['id']);
103 * Verify return when course groupmode set to 'separate groups'.
105 public function test_user_get_user_details_courses_groupmode_separate() {
106 $this->resetAfterTest();
108 // Enrol 2 users into a course with groupmode set to 'separate groups'.
109 // The users are not in any groups, so profiles should be hidden (same as if they were in separate groups).
110 $user1 = $this->getDataGenerator()->create_user();
111 $user2 = $this->getDataGenerator()->create_user();
112 $course = $this->getDataGenerator()->create_course((object) ['groupmode' => 1]);
113 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
);
114 $this->getDataGenerator()->enrol_user($user2->id
, $course->id
);
116 $this->setUser($user1);
117 $this->assertNull(user_get_user_details_courses($user2));
121 * Verify return when course groupmode set to 'visible groups'.
123 public function test_user_get_user_details_courses_groupmode_visible() {
124 $this->resetAfterTest();
126 // Enrol 2 users into a course with groupmode set to 'visible groups'.
127 // The users are not in any groups, and profiles should be visible because of the groupmode.
128 $user1 = $this->getDataGenerator()->create_user();
129 $user2 = $this->getDataGenerator()->create_user();
130 $course = $this->getDataGenerator()->create_course((object) ['groupmode' => 2]);
131 $this->getDataGenerator()->enrol_user($user1->id
, $course->id
);
132 $this->getDataGenerator()->enrol_user($user2->id
, $course->id
);
134 $this->setUser($user1);
135 $userdetails = user_get_user_details_courses($user2);
136 $this->assertIsArray($userdetails);
137 $this->assertEquals($user2->id
, $userdetails['id']);
141 * Test user_update_user.
143 public function test_user_update_user() {
146 $this->resetAfterTest();
148 // Create user and modify user profile.
149 $user = $this->getDataGenerator()->create_user();
150 $user->firstname
= 'Test';
151 $user->password
= 'M00dLe@T';
153 // Update user and capture event.
154 $sink = $this->redirectEvents();
155 user_update_user($user);
156 $events = $sink->get_events();
158 $event = array_pop($events);
160 // Test updated value.
161 $dbuser = $DB->get_record('user', array('id' => $user->id
));
162 $this->assertSame($user->firstname
, $dbuser->firstname
);
163 $this->assertNotSame('M00dLe@T', $dbuser->password
);
166 $this->assertInstanceOf('\core\event\user_updated', $event);
167 $this->assertSame($user->id
, $event->objectid
);
168 $this->assertSame('user_updated', $event->get_legacy_eventname());
169 $this->assertEventLegacyData($dbuser, $event);
170 $this->assertEquals(context_user
::instance($user->id
), $event->get_context());
171 $expectedlogdata = array(SITEID
, 'user', 'update', 'view.php?id='.$user->id
, '');
172 $this->assertEventLegacyLogData($expectedlogdata, $event);
174 // Update user with no password update.
175 $password = $user->password
= hash_internal_user_password('M00dLe@T');
176 user_update_user($user, false);
177 $dbuser = $DB->get_record('user', array('id' => $user->id
));
178 $this->assertSame($password, $dbuser->password
);
180 // Verify event is not triggred by user_update_user when needed.
181 $sink = $this->redirectEvents();
182 user_update_user($user, false, false);
183 $events = $sink->get_events();
185 $this->assertCount(0, $events);
187 // With password, there should be 1 event.
188 $sink = $this->redirectEvents();
189 user_update_user($user, true, false);
190 $events = $sink->get_events();
192 $this->assertCount(1, $events);
193 $event = array_pop($events);
194 $this->assertInstanceOf('\core\event\user_password_updated', $event);
196 // Test user data validation.
197 $user->username
= 'johndoe123';
198 $user->auth
= 'shibolth';
199 $user->country
= 'WW';
201 $user->theme
= 'somewrongthemename';
202 $user->timezone
= '30.5';
203 $debugmessages = $this->getDebuggingMessages();
204 user_update_user($user, true, false);
205 $this->assertDebuggingCalledCount(5, $debugmessages);
207 // Now, with valid user data.
208 $user->username
= 'johndoe321';
209 $user->auth
= 'shibboleth';
210 $user->country
= 'AU';
212 $user->theme
= 'classic';
213 $user->timezone
= 'Australia/Perth';
214 user_update_user($user, true, false);
215 $this->assertDebuggingNotCalled();
221 public function test_create_users() {
224 $this->resetAfterTest();
227 'username' => 'usernametest1',
228 'password' => 'Moodle2012!',
229 'idnumber' => 'idnumbertest1',
230 'firstname' => 'First Name User Test 1',
231 'lastname' => 'Last Name User Test 1',
232 'middlename' => 'Middle Name User Test 1',
233 'lastnamephonetic' => '最後のお名前のテスト一号',
234 'firstnamephonetic' => 'お名前のテスト一号',
235 'alternatename' => 'Alternate Name User Test 1',
236 'email' => 'usertest1@example.com',
237 'description' => 'This is a description for user 1',
242 // Create user and capture event.
243 $sink = $this->redirectEvents();
244 $user['id'] = user_create_user($user);
245 $events = $sink->get_events();
247 $event = array_pop($events);
249 // Test user info in DB.
250 $dbuser = $DB->get_record('user', array('id' => $user['id']));
251 $this->assertEquals($dbuser->username
, $user['username']);
252 $this->assertEquals($dbuser->idnumber
, $user['idnumber']);
253 $this->assertEquals($dbuser->firstname
, $user['firstname']);
254 $this->assertEquals($dbuser->lastname
, $user['lastname']);
255 $this->assertEquals($dbuser->email
, $user['email']);
256 $this->assertEquals($dbuser->description
, $user['description']);
257 $this->assertEquals($dbuser->city
, $user['city']);
258 $this->assertEquals($dbuser->country
, $user['country']);
261 $this->assertInstanceOf('\core\event\user_created', $event);
262 $this->assertEquals($user['id'], $event->objectid
);
263 $this->assertEquals('user_created', $event->get_legacy_eventname());
264 $this->assertEquals(context_user
::instance($user['id']), $event->get_context());
265 $this->assertEventLegacyData($dbuser, $event);
266 $expectedlogdata = array(SITEID
, 'user', 'add', '/view.php?id='.$event->objectid
, fullname($dbuser));
267 $this->assertEventLegacyLogData($expectedlogdata, $event);
269 // Verify event is not triggred by user_create_user when needed.
270 $user = array('username' => 'usernametest2'); // Create another user.
271 $sink = $this->redirectEvents();
272 user_create_user($user, true, false);
273 $events = $sink->get_events();
275 $this->assertCount(0, $events);
277 // Test user data validation, first some invalid data.
278 $user['username'] = 'johndoe123';
279 $user['auth'] = 'shibolth';
280 $user['country'] = 'WW';
281 $user['lang'] = 'xy';
282 $user['theme'] = 'somewrongthemename';
283 $user['timezone'] = '-30.5';
284 $debugmessages = $this->getDebuggingMessages();
285 $user['id'] = user_create_user($user, true, false);
286 $this->assertDebuggingCalledCount(5, $debugmessages);
287 $dbuser = $DB->get_record('user', array('id' => $user['id']));
288 $this->assertEquals($dbuser->country
, 0);
289 $this->assertEquals($dbuser->lang
, 'en');
290 $this->assertEquals($dbuser->timezone
, '');
292 // Now, with valid user data.
293 $user['username'] = 'johndoe321';
294 $user['auth'] = 'shibboleth';
295 $user['country'] = 'AU';
296 $user['lang'] = 'en';
297 $user['theme'] = 'classic';
298 $user['timezone'] = 'Australia/Perth';
299 user_create_user($user, true, false);
300 $this->assertDebuggingNotCalled();
304 * Test that creating users populates default values
306 * @covers ::user_create_user
308 public function test_user_create_user_default_values(): void
{
311 $this->resetAfterTest();
313 // Update default values for city/country (both initially empty).
314 set_config('defaultcity', 'Nadi');
315 set_config('country', 'FJ');
317 $userid = user_create_user((object) [
318 'username' => 'newuser',
321 $user = core_user
::get_user($userid);
322 $this->assertEquals($CFG->calendartype
, $user->calendartype
);
323 $this->assertEquals($CFG->defaultpreference_maildisplay
, $user->maildisplay
);
324 $this->assertEquals($CFG->defaultpreference_mailformat
, $user->mailformat
);
325 $this->assertEquals($CFG->defaultpreference_maildigest
, $user->maildigest
);
326 $this->assertEquals($CFG->defaultpreference_autosubscribe
, $user->autosubscribe
);
327 $this->assertEquals($CFG->defaultpreference_trackforums
, $user->trackforums
);
328 $this->assertEquals($CFG->lang
, $user->lang
);
329 $this->assertEquals($CFG->defaultcity
, $user->city
);
330 $this->assertEquals($CFG->country
, $user->country
);
334 * Test that {@link user_create_user()} throws exception when invalid username is provided.
336 * @dataProvider data_create_user_invalid_username
337 * @param string $username Invalid username
338 * @param string $expectmessage Expected exception message
340 public function test_create_user_invalid_username($username, $expectmessage) {
343 $this->resetAfterTest();
344 $CFG->extendedusernamechars
= false;
347 'username' => $username,
350 $this->expectException('moodle_exception');
351 $this->expectExceptionMessage($expectmessage);
353 user_create_user($user);
357 * Data provider for {@link self::test_create_user_invalid_username()}.
361 public function data_create_user_invalid_username() {
365 'The username cannot be blank',
367 'only_whitespace' => [
369 'The username cannot be blank',
373 'The username must be in lower case',
375 'extended_chars' => [
377 'The given username contains invalid characters',
383 * Test function user_count_login_failures().
385 public function test_user_count_login_failures() {
386 $this->resetAfterTest();
387 $user = $this->getDataGenerator()->create_user();
388 $this->assertEquals(0, get_user_preferences('login_failed_count_since_success', 0, $user));
389 for ($i = 0; $i < 10; $i++
) {
390 login_attempt_failed($user);
392 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user));
393 $count = user_count_login_failures($user); // Reset count.
394 $this->assertEquals(10, $count);
395 $this->assertEquals(0, get_user_preferences('login_failed_count_since_success', 0, $user));
397 for ($i = 0; $i < 10; $i++
) {
398 login_attempt_failed($user);
400 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user));
401 $count = user_count_login_failures($user, false); // Do not reset count.
402 $this->assertEquals(10, $count);
403 $this->assertEquals(10, get_user_preferences('login_failed_count_since_success', 0, $user));
407 * Test function user_add_password_history().
409 public function test_user_add_password_history() {
412 $this->resetAfterTest();
414 $user1 = $this->getDataGenerator()->create_user();
415 $user2 = $this->getDataGenerator()->create_user();
416 $user3 = $this->getDataGenerator()->create_user();
417 $DB->delete_records('user_password_history', array());
419 set_config('passwordreuselimit', 0);
421 user_add_password_history($user1->id
, 'pokus');
422 $this->assertEquals(0, $DB->count_records('user_password_history'));
424 // Test adding and discarding of old.
426 set_config('passwordreuselimit', 3);
428 user_add_password_history($user1->id
, 'pokus');
429 $this->assertEquals(1, $DB->count_records('user_password_history'));
430 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id
)));
432 user_add_password_history($user1->id
, 'pokus2');
433 user_add_password_history($user1->id
, 'pokus3');
434 user_add_password_history($user1->id
, 'pokus4');
435 $this->assertEquals(3, $DB->count_records('user_password_history'));
436 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user1->id
)));
438 user_add_password_history($user2->id
, 'pokus1');
439 $this->assertEquals(4, $DB->count_records('user_password_history'));
440 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user1->id
)));
441 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user2->id
)));
443 user_add_password_history($user2->id
, 'pokus2');
444 user_add_password_history($user2->id
, 'pokus3');
445 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user2->id
)));
447 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id
), 'timecreated ASC, id ASC'));
448 user_add_password_history($user2->id
, 'pokus4');
449 $this->assertEquals(3, $DB->count_records('user_password_history', array('userid' => $user2->id
)));
450 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id
), 'timecreated ASC, id ASC'));
452 $removed = array_shift($ids);
453 $added = array_pop($newids);
454 $this->assertSame($ids, $newids);
455 $this->assertGreaterThan($removed, $added);
457 // Test disabling prevents changes.
459 set_config('passwordreuselimit', 0);
461 $this->assertEquals(6, $DB->count_records('user_password_history'));
463 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id
), 'timecreated ASC, id ASC'));
464 user_add_password_history($user2->id
, 'pokus5');
465 user_add_password_history($user3->id
, 'pokus1');
466 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id
), 'timecreated ASC, id ASC'));
467 $this->assertSame($ids, $newids);
468 $this->assertEquals(6, $DB->count_records('user_password_history'));
470 set_config('passwordreuselimit', -1);
472 $ids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id
), 'timecreated ASC, id ASC'));
473 user_add_password_history($user2->id
, 'pokus6');
474 user_add_password_history($user3->id
, 'pokus6');
475 $newids = array_keys($DB->get_records('user_password_history', array('userid' => $user2->id
), 'timecreated ASC, id ASC'));
476 $this->assertSame($ids, $newids);
477 $this->assertEquals(6, $DB->count_records('user_password_history'));
481 * Test function user_add_password_history().
483 public function test_user_is_previously_used_password() {
486 $this->resetAfterTest();
488 $user1 = $this->getDataGenerator()->create_user();
489 $user2 = $this->getDataGenerator()->create_user();
490 $DB->delete_records('user_password_history', array());
492 set_config('passwordreuselimit', 0);
494 user_add_password_history($user1->id
, 'pokus');
495 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus'));
497 set_config('passwordreuselimit', 3);
499 user_add_password_history($user2->id
, 'pokus1');
500 user_add_password_history($user2->id
, 'pokus2');
502 user_add_password_history($user1->id
, 'pokus1');
503 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus1'));
504 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus2'));
505 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus3'));
506 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus4'));
508 user_add_password_history($user1->id
, 'pokus2');
509 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus1'));
510 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus2'));
511 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus3'));
512 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus4'));
514 user_add_password_history($user1->id
, 'pokus3');
515 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus1'));
516 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus2'));
517 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus3'));
518 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus4'));
520 user_add_password_history($user1->id
, 'pokus4');
521 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus1'));
522 $this->assertTrue(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'));
526 set_config('passwordreuselimit', 2);
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'));
533 set_config('passwordreuselimit', 3);
535 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus1'));
536 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus2'));
537 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus3'));
538 $this->assertTrue(user_is_previously_used_password($user1->id
, 'pokus4'));
540 set_config('passwordreuselimit', 0);
542 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus1'));
543 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus2'));
544 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus3'));
545 $this->assertFalse(user_is_previously_used_password($user1->id
, 'pokus4'));
549 * Test that password history is deleted together with user.
551 public function test_delete_of_hashes_on_user_delete() {
554 $this->resetAfterTest();
556 $user1 = $this->getDataGenerator()->create_user();
557 $user2 = $this->getDataGenerator()->create_user();
558 $DB->delete_records('user_password_history', array());
560 set_config('passwordreuselimit', 3);
562 user_add_password_history($user1->id
, 'pokus');
563 user_add_password_history($user2->id
, 'pokus1');
564 user_add_password_history($user2->id
, 'pokus2');
566 $this->assertEquals(3, $DB->count_records('user_password_history'));
567 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id
)));
568 $this->assertEquals(2, $DB->count_records('user_password_history', array('userid' => $user2->id
)));
571 $this->assertEquals(1, $DB->count_records('user_password_history'));
572 $this->assertEquals(1, $DB->count_records('user_password_history', array('userid' => $user1->id
)));
573 $this->assertEquals(0, $DB->count_records('user_password_history', array('userid' => $user2->id
)));
577 * Test user_list_view function
579 public function test_user_list_view() {
581 $this->resetAfterTest();
583 // Course without sections.
584 $course = $this->getDataGenerator()->create_course();
585 $context = context_course
::instance($course->id
);
587 $this->setAdminUser();
589 // Redirect events to the sink, so we can recover them later.
590 $sink = $this->redirectEvents();
592 user_list_view($course, $context);
593 $events = $sink->get_events();
594 $this->assertCount(1, $events);
595 $event = reset($events);
597 // Check the event details are correct.
598 $this->assertInstanceOf('\core\event\user_list_viewed', $event);
599 $this->assertEquals($context, $event->get_context());
600 $this->assertEquals($course->shortname
, $event->other
['courseshortname']);
601 $this->assertEquals($course->fullname
, $event->other
['coursefullname']);
606 * Test setting the user menu avatar size.
608 public function test_user_menu_custom_avatar_size() {
610 $this->resetAfterTest(true);
615 $user = $this->getDataGenerator()->create_user();
616 $this->setUser($user);
617 $opts = user_get_user_navigation_info($user, $PAGE, array('avatarsize' => $testsize));
618 $avatarhtml = $opts->metadata
['useravatar'];
621 preg_match('/size-100/', $avatarhtml, $matches);
622 $this->assertCount(1, $matches);
626 * Test user_can_view_profile
628 public function test_user_can_view_profile() {
631 $this->resetAfterTest();
633 // Create five users.
634 $user1 = $this->getDataGenerator()->create_user();
635 $user2 = $this->getDataGenerator()->create_user();
636 $user3 = $this->getDataGenerator()->create_user();
637 $user4 = $this->getDataGenerator()->create_user();
638 $user5 = $this->getDataGenerator()->create_user();
639 $user6 = $this->getDataGenerator()->create_user(array('deleted' => 1));
640 $user7 = $this->getDataGenerator()->create_user();
641 $user8 = $this->getDataGenerator()->create_user();
642 $user8->id
= 0; // Visitor.
644 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
645 // Add the course creator role to the course contact and assign a user to that role.
646 $CFG->coursecontact
= '2';
647 $coursecreatorrole = $DB->get_record('role', array('shortname' => 'coursecreator'));
648 $this->getDataGenerator()->role_assign($coursecreatorrole->id
, $user7->id
);
650 // Create two courses.
651 $course1 = $this->getDataGenerator()->create_course();
652 $course2 = $this->getDataGenerator()->create_course();
653 $coursecontext = context_course
::instance($course2->id
);
654 // Prepare another course with separate groups and groupmodeforce set to true.
655 $record = new stdClass();
656 $record->groupmode
= 1;
657 $record->groupmodeforce
= 1;
658 $course3 = $this->getDataGenerator()->create_course($record);
659 // Enrol users 1 and 2 in first course.
660 $this->getDataGenerator()->enrol_user($user1->id
, $course1->id
);
661 $this->getDataGenerator()->enrol_user($user2->id
, $course1->id
);
662 // Enrol users 2 and 3 in second course.
663 $this->getDataGenerator()->enrol_user($user2->id
, $course2->id
);
664 $this->getDataGenerator()->enrol_user($user3->id
, $course2->id
);
665 // Enrol users 1, 4, and 5 into course 3.
666 $this->getDataGenerator()->enrol_user($user1->id
, $course3->id
);
667 $this->getDataGenerator()->enrol_user($user4->id
, $course3->id
);
668 $this->getDataGenerator()->enrol_user($user5->id
, $course3->id
);
670 // 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).
671 $this->setUser($user3);
672 $this->assertFalse(user_can_view_profile($user1, $course2));
673 $this->assertFalse(user_can_view_profile($user1, $course1));
675 // Remove capability moodle/user:viewdetails in course 2.
676 assign_capability('moodle/user:viewdetails', CAP_PROHIBIT
, $studentrole->id
, $coursecontext);
677 // Set current user to user 1.
678 $this->setUser($user1);
679 // User 1 can see User 1's profile.
680 $this->assertTrue(user_can_view_profile($user1));
682 $tempcfg = $CFG->forceloginforprofiles
;
683 $CFG->forceloginforprofiles
= 0;
684 // Not forced to log in to view profiles, should be able to see all profiles besides user 6.
685 $users = array($user1, $user2, $user3, $user4, $user5, $user7);
686 foreach ($users as $user) {
687 $this->assertTrue(user_can_view_profile($user));
690 $CFG->forceloginforprofiles
= $tempcfg;
692 // User 1 can not see user 6 as they have been deleted.
693 $this->assertFalse(user_can_view_profile($user6));
694 // User 1 can see User 7 as they are a course contact.
695 $this->assertTrue(user_can_view_profile($user7));
696 // User 1 is in a course with user 2 and has the right capability - return true.
697 $this->assertTrue(user_can_view_profile($user2));
698 // User 1 is not in a course with user 3 - return false.
699 $this->assertFalse(user_can_view_profile($user3));
701 // Set current user to user 2.
702 $this->setUser($user2);
703 // User 2 is in a course with user 3 but does not have the right capability - return false.
704 $this->assertFalse(user_can_view_profile($user3));
706 // Set user 1 in one group and users 4 and 5 in another group.
707 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course3->id
));
708 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course3->id
));
709 groups_add_member($group1->id
, $user1->id
);
710 groups_add_member($group2->id
, $user4->id
);
711 groups_add_member($group2->id
, $user5->id
);
712 $this->setUser($user1);
713 // Check that user 1 can not see user 4.
714 $this->assertFalse(user_can_view_profile($user4));
715 // Check that user 5 can see user 4.
716 $this->setUser($user5);
717 $this->assertTrue(user_can_view_profile($user4));
719 // Test the user:viewalldetails cap check using the course creator role which, by default, can't see student profiles.
720 $this->setUser($user7);
721 $this->assertFalse(user_can_view_profile($user4));
722 assign_capability('moodle/user:viewalldetails', CAP_ALLOW
, $coursecreatorrole->id
, context_system
::instance()->id
, true);
723 reload_all_capabilities();
724 $this->assertTrue(user_can_view_profile($user4));
725 unassign_capability('moodle/user:viewalldetails', $coursecreatorrole->id
, $coursecontext->id
);
726 reload_all_capabilities();
728 $CFG->coursecontact
= null;
730 // Visitor (Not a guest user, userid=0).
731 $CFG->forceloginforprofiles
= 1;
732 $this->setUser($user8);
733 $this->assertFalse(user_can_view_profile($user1));
735 // Let us test with guest user.
736 $this->setGuestUser();
737 $CFG->forceloginforprofiles
= 1;
738 foreach ($users as $user) {
739 $this->assertFalse(user_can_view_profile($user));
742 // Even with cap, still guests should not be allowed in.
743 $guestrole = $DB->get_records_menu('role', array('shortname' => 'guest'), 'id', 'archetype, id');
744 assign_capability('moodle/user:viewdetails', CAP_ALLOW
, $guestrole['guest'], context_system
::instance()->id
, true);
745 reload_all_capabilities();
746 foreach ($users as $user) {
747 $this->assertFalse(user_can_view_profile($user));
750 $CFG->forceloginforprofiles
= 0;
751 foreach ($users as $user) {
752 $this->assertTrue(user_can_view_profile($user));
755 // Let us test with Visitor user.
756 $this->setUser($user8);
757 $CFG->forceloginforprofiles
= 1;
758 foreach ($users as $user) {
759 $this->assertFalse(user_can_view_profile($user));
762 $CFG->forceloginforprofiles
= 0;
763 foreach ($users as $user) {
764 $this->assertTrue(user_can_view_profile($user));
767 // Testing non-shared courses where capabilities are met, using system role overrides.
768 $CFG->forceloginforprofiles
= $tempcfg;
769 $course4 = $this->getDataGenerator()->create_course();
770 $this->getDataGenerator()->enrol_user($user1->id
, $course4->id
);
772 // Assign a manager role at the system context.
773 $managerrole = $DB->get_record('role', array('shortname' => 'manager'));
774 $user9 = $this->getDataGenerator()->create_user();
775 $this->getDataGenerator()->role_assign($managerrole->id
, $user9->id
);
777 // Make sure viewalldetails and viewdetails are overridden to 'prevent' (i.e. can be overridden at a lower context).
778 $systemcontext = context_system
::instance();
779 assign_capability('moodle/user:viewdetails', CAP_PREVENT
, $managerrole->id
, $systemcontext, true);
780 assign_capability('moodle/user:viewalldetails', CAP_PREVENT
, $managerrole->id
, $systemcontext, true);
782 // And override these to 'Allow' in a specific course.
783 $course4context = context_course
::instance($course4->id
);
784 assign_capability('moodle/user:viewalldetails', CAP_ALLOW
, $managerrole->id
, $course4context, true);
785 assign_capability('moodle/user:viewdetails', CAP_ALLOW
, $managerrole->id
, $course4context, true);
787 // The manager now shouldn't have viewdetails in the system or user context.
788 $this->setUser($user9);
789 $user1context = context_user
::instance($user1->id
);
790 $this->assertFalse(has_capability('moodle/user:viewdetails', $systemcontext));
791 $this->assertFalse(has_capability('moodle/user:viewdetails', $user1context));
793 // Confirm that user_can_view_profile() returns true for $user1 when called without $course param. It should find $course1.
794 $this->assertTrue(user_can_view_profile($user1));
796 // Confirm this also works when restricting scope to just that course.
797 $this->assertTrue(user_can_view_profile($user1, $course4));
801 * Test user_get_user_details
803 public function test_user_get_user_details() {
806 $this->resetAfterTest();
808 // Create user and modify user profile.
809 $teacher = $this->getDataGenerator()->create_user();
810 $student = $this->getDataGenerator()->create_user();
811 $studentfullname = fullname($student);
813 $course1 = $this->getDataGenerator()->create_course();
814 $coursecontext = context_course
::instance($course1->id
);
815 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
816 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
817 $this->getDataGenerator()->enrol_user($teacher->id
, $course1->id
);
818 $this->getDataGenerator()->enrol_user($student->id
, $course1->id
);
819 role_assign($teacherrole->id
, $teacher->id
, $coursecontext->id
);
820 role_assign($studentrole->id
, $student->id
, $coursecontext->id
);
822 accesslib_clear_all_caches_for_unit_testing();
824 // Get student details as a user with super system capabilities.
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']);
830 $this->setUser($teacher);
831 // Get student details as a user who can only see this user in a course.
832 $result = user_get_user_details($student, $course1);
833 $this->assertEquals($student->id
, $result['id']);
834 $this->assertEquals($studentfullname, $result['fullname']);
835 $this->assertEquals($course1->id
, $result['enrolledcourses'][0]['id']);
837 // Get student details with required fields.
838 $result = user_get_user_details($student, $course1, array('id', 'fullname'));
839 $this->assertCount(2, $result);
840 $this->assertEquals($student->id
, $result['id']);
841 $this->assertEquals($studentfullname, $result['fullname']);
843 // Get exception for invalid required fields.
844 $this->expectException('moodle_exception');
845 $result = user_get_user_details($student, $course1, array('wrongrequiredfield'));
849 * Regression test for MDL-57840.
851 * Ensure the fields "auth, confirmed, idnumber, lang, theme, timezone and mailformat" are present when
852 * calling user_get_user_details() function.
854 public function test_user_get_user_details_missing_fields() {
857 $this->resetAfterTest(true);
858 $this->setAdminUser(); // We need capabilities to view the data.
859 $user = self
::getDataGenerator()->create_user([
862 'idnumber' => 'someidnumber',
864 'theme' => $CFG->theme
,
869 // Fields that should get by default.
870 $got = user_get_user_details($user);
871 self
::assertSame('email', $got['auth']);
872 self
::assertSame('0', $got['confirmed']);
873 self
::assertSame('someidnumber', $got['idnumber']);
874 self
::assertSame('en', $got['lang']);
875 self
::assertSame($CFG->theme
, $got['theme']);
876 self
::assertSame('5', $got['timezone']);
877 self
::assertSame('0', $got['mailformat']);