Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

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