MDL-74463 enrol_lti: fix location of scopes in registration json
[moodle.git] / user / tests / userlib_test.php
blobc024be9fa452be3582ec16d38f96b47668bb63fb
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.
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/>.
17 /**
18 * Unit tests for user/lib.php.
20 * @package core_user
21 * @category phpunit
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();
28 global $CFG;
29 require_once($CFG->dirroot.'/user/lib.php');
31 /**
32 * Unit tests for user lib api.
34 * @package core_user
35 * @category phpunit
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 {
40 /**
41 * Test user_get_user_details_courses
43 public function test_user_get_user_details_courses() {
44 global $DB;
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);
82 /**
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() {
144 global $DB;
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();
157 $sink->close();
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);
165 // Test event.
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();
184 $sink->close();
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();
191 $sink->close();
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';
200 $user->lang = 'xy';
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';
211 $user->lang = 'en';
212 $user->theme = 'classic';
213 $user->timezone = 'Australia/Perth';
214 user_update_user($user, true, false);
215 $this->assertDebuggingNotCalled();
219 * Test create_users.
221 public function test_create_users() {
222 global $DB;
224 $this->resetAfterTest();
226 $user = array(
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',
238 'city' => 'Perth',
239 'country' => 'AU'
242 // Create user and capture event.
243 $sink = $this->redirectEvents();
244 $user['id'] = user_create_user($user);
245 $events = $sink->get_events();
246 $sink->close();
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']);
260 // Test event.
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();
274 $sink->close();
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 {
309 global $CFG;
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',
319 ], false, false);
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) {
341 global $CFG;
343 $this->resetAfterTest();
344 $CFG->extendedusernamechars = false;
346 $user = [
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()}.
359 * @return array
361 public function data_create_user_invalid_username() {
362 return [
363 'empty_string' => [
365 'The username cannot be blank',
367 'only_whitespace' => [
368 "\t\t \t\n ",
369 'The username cannot be blank',
371 'lower_case' => [
372 'Mudrd8mz',
373 'The username must be in lower case',
375 'extended_chars' => [
376 'dmudrák',
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() {
410 global $DB;
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() {
484 global $DB;
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() {
552 global $DB;
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)));
570 delete_user($user2);
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() {
609 global $PAGE;
610 $this->resetAfterTest(true);
612 $testsize = 100;
614 $PAGE->set_url('/');
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'];
620 $matches = [];
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() {
629 global $DB, $CFG;
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));
689 // Restore setting.
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() {
804 global $DB;
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() {
855 global $CFG;
857 $this->resetAfterTest(true);
858 $this->setAdminUser(); // We need capabilities to view the data.
859 $user = self::getDataGenerator()->create_user([
860 'auth' => 'email',
861 'confirmed' => '0',
862 'idnumber' => 'someidnumber',
863 'lang' => 'en',
864 'theme' => $CFG->theme,
865 'timezone' => '5',
866 'mailformat' => '0',
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']);