Proyectos de Subversion Moodle

Rev

Rev 11 | | 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
/**
18
 * User external PHPunit tests
19
 *
20
 * @package    core_user
21
 * @category   external
22
 * @copyright  2012 Jerome Mouneyrac
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 * @since Moodle 2.4
25
 */
26
 
27
namespace core_user;
28
 
29
use core_external\external_api;
30
use core_files_external;
31
use core_user_external;
32
use externallib_advanced_testcase;
33
 
34
defined('MOODLE_INTERNAL') || die();
35
 
36
global $CFG;
37
 
38
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
39
require_once($CFG->dirroot . '/user/externallib.php');
40
require_once($CFG->dirroot . '/files/externallib.php');
41
 
42
/**
43
 * Tests for the user external functions.
44
 *
45
 * @package core_user
46
 * @covers \core_user_external
47
 */
48
final class externallib_test extends externallib_advanced_testcase {
49
 
50
    /**
51
     * Test get_users
52
     */
11 efrain 53
    public function test_get_users(): void {
1 efrain 54
        global $USER, $CFG;
55
 
56
        $this->resetAfterTest(true);
57
 
58
        $course = self::getDataGenerator()->create_course();
59
 
60
        $user1 = array(
61
            'username' => 'usernametest1',
62
            'idnumber' => 'idnumbertest1',
63
            'firstname' => 'First Name User Test 1',
64
            'lastname' => 'Last Name User Test 1',
65
            'email' => 'usertest1@example.com',
66
            'address' => '2 Test Street Perth 6000 WA',
67
            'phone1' => '01010101010',
68
            'phone2' => '02020203',
69
            'department' => 'Department of user 1',
70
            'institution' => 'Institution of user 1',
71
            'description' => 'This is a description for user 1',
72
            'descriptionformat' => FORMAT_MOODLE,
73
            'city' => 'Perth',
74
            'country' => 'AU'
75
            );
76
 
77
        $user1 = self::getDataGenerator()->create_user($user1);
78
        set_config('usetags', 1);
79
        require_once($CFG->dirroot . '/user/editlib.php');
80
        $user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking');
81
        useredit_update_interests($user1, $user1->interests);
82
 
83
        $user2 = self::getDataGenerator()->create_user(
84
                array('username' => 'usernametest2', 'idnumber' => 'idnumbertest2'));
85
 
86
        $generatedusers = array();
87
        $generatedusers[$user1->id] = $user1;
88
        $generatedusers[$user2->id] = $user2;
89
 
90
        $context = \context_course::instance($course->id);
91
        $roleid = $this->assignUserCapability('moodle/user:viewdetails', $context->id);
92
 
93
        // Enrol the users in the course.
94
        $this->getDataGenerator()->enrol_user($user1->id, $course->id, $roleid);
95
        $this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleid);
96
        $this->getDataGenerator()->enrol_user($USER->id, $course->id, $roleid);
97
 
98
        // call as admin and receive all possible fields.
99
        $this->setAdminUser();
100
 
101
        $searchparams = array(
102
            array('key' => 'invalidkey', 'value' => 'invalidkey'),
103
            array('key' => 'email', 'value' => $user1->email),
104
            array('key' => 'firstname', 'value' => $user1->firstname));
105
 
106
        // Call the external function.
107
        $result = core_user_external::get_users($searchparams);
108
 
109
        // We need to execute the return values cleaning process to simulate the web service server
110
        $result = external_api::clean_returnvalue(core_user_external::get_users_returns(), $result);
111
 
112
        // Check we retrieve the good total number of enrolled users + no error on capability.
113
        $expectedreturnedusers = 1;
114
        $returnedusers = $result['users'];
115
        $this->assertEquals($expectedreturnedusers, count($returnedusers));
116
 
117
        foreach($returnedusers as $returneduser) {
118
            $generateduser = ($returneduser['id'] == $USER->id) ?
119
                                $USER : $generatedusers[$returneduser['id']];
120
            $this->assertEquals($generateduser->username, $returneduser['username']);
121
            if (!empty($generateduser->idnumber)) {
122
                $this->assertEquals($generateduser->idnumber, $returneduser['idnumber']);
123
            }
124
            $this->assertEquals($generateduser->firstname, $returneduser['firstname']);
125
            $this->assertEquals($generateduser->lastname, $returneduser['lastname']);
126
            if ($generateduser->email != $USER->email) { // Don't check the tmp modified $USER email.
127
                $this->assertEquals($generateduser->email, $returneduser['email']);
128
            }
129
            if (!empty($generateduser->address)) {
130
                $this->assertEquals($generateduser->address, $returneduser['address']);
131
            }
132
            if (!empty($generateduser->phone1)) {
133
                $this->assertEquals($generateduser->phone1, $returneduser['phone1']);
134
            }
135
            if (!empty($generateduser->phone2)) {
136
                $this->assertEquals($generateduser->phone2, $returneduser['phone2']);
137
            }
138
            if (!empty($generateduser->department)) {
139
                $this->assertEquals($generateduser->department, $returneduser['department']);
140
            }
141
            if (!empty($generateduser->institution)) {
142
                $this->assertEquals($generateduser->institution, $returneduser['institution']);
143
            }
144
            if (!empty($generateduser->description)) {
145
                $this->assertEquals($generateduser->description, $returneduser['description']);
146
            }
147
            if (!empty($generateduser->descriptionformat)) {
148
                $this->assertEquals(FORMAT_HTML, $returneduser['descriptionformat']);
149
            }
150
            if (!empty($generateduser->city)) {
151
                $this->assertEquals($generateduser->city, $returneduser['city']);
152
            }
153
            if (!empty($generateduser->country)) {
154
                $this->assertEquals($generateduser->country, $returneduser['country']);
155
            }
156
            if (!empty($CFG->usetags) and !empty($generateduser->interests)) {
157
                $this->assertEquals(implode(', ', $generateduser->interests), $returneduser['interests']);
158
            }
159
        }
160
 
161
        // Test the invalid key warning.
162
        $warnings = $result['warnings'];
163
        $this->assertEquals(count($warnings), 1);
164
        $warning = array_pop($warnings);
165
        $this->assertEquals($warning['item'], 'invalidkey');
166
        $this->assertEquals($warning['warningcode'], 'invalidfieldparameter');
167
 
168
        // Test sending twice the same search field.
169
        try {
170
            $searchparams = array(
171
            array('key' => 'firstname', 'value' => 'Canard'),
172
            array('key' => 'email', 'value' => $user1->email),
173
            array('key' => 'firstname', 'value' => $user1->firstname));
174
 
175
            // Call the external function.
176
            $result = core_user_external::get_users($searchparams);
177
            $this->fail('Expecting \'keyalreadyset\' moodle_exception to be thrown.');
178
        } catch (\moodle_exception $e) {
179
            $this->assertEquals('keyalreadyset', $e->errorcode);
180
        } catch (\Exception $e) {
181
            $this->fail('Expecting \'keyalreadyset\' moodle_exception to be thrown.');
182
        }
183
    }
184
 
185
    /**
186
     * Test get_users_by_field
187
     */
188
    public function test_get_users_by_field(): void {
189
        global $USER, $CFG;
190
 
191
        $this->resetAfterTest(true);
192
 
193
        $generator = self::getDataGenerator();
194
 
195
        // Create complex user profile field supporting multi-lang.
196
        filter_set_global_state('multilang', TEXTFILTER_ON);
1441 ariadna 197
        filter_set_applies_to_strings('multilang', true);
198
 
1 efrain 199
        $name = '<span lang="en" class="multilang">Employment status</span>'.
200
            '<span lang="es" class="multilang">Estado de Empleo</span>';
201
        $statuses = 'UE\nSE\n<span lang="en" class="multilang">Other</span><span lang="es" class="multilang">Otro</span>';
202
        $generator->create_custom_profile_field(
203
            [
204
                'datatype' => 'menu',
205
                'shortname' => 'employmentstatus',
206
                'name' => $name,
207
                'param1' => $statuses
208
            ]
209
        );
210
 
211
        $course = $generator->create_course();
212
        $user1 = array(
213
            'username' => 'usernametest1',
214
            'idnumber' => 'idnumbertest1',
215
            'firstname' => 'First Name User Test 1',
216
            'lastname' => 'Last Name User Test 1',
217
            'email' => 'usertest1@example.com',
218
            'address' => '2 Test Street Perth 6000 WA',
219
            'phone1' => '01010101010',
220
            'phone2' => '02020203',
221
            'department' => 'Department of user 1',
222
            'institution' => 'Institution of user 1',
223
            'description' => 'This is a description for user 1',
224
            'descriptionformat' => FORMAT_MOODLE,
225
            'city' => 'Perth',
226
            'country' => 'AU',
227
            'profile_field_jobposition' => 'Manager',
228
            'profile_field_employmentstatus' => explode('\n', $statuses)[2],
229
        );
230
        $user1 = $generator->create_user($user1);
231
        if (!empty($CFG->usetags)) {
232
            require_once($CFG->dirroot . '/user/editlib.php');
233
            $user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking');
234
            useredit_update_interests($user1, $user1->interests);
235
        }
236
        $user2 = $generator->create_user(
237
                array('username' => 'usernametest2', 'idnumber' => 'idnumbertest2'));
238
 
239
        $generatedusers = array();
240
        $generatedusers[$user1->id] = $user1;
241
        $generatedusers[$user2->id] = $user2;
242
 
243
        $context = \context_course::instance($course->id);
244
        $roleid = $this->assignUserCapability('moodle/user:viewdetails', $context->id);
245
 
246
        // Enrol the users in the course.
247
        $generator->enrol_user($user1->id, $course->id, $roleid, 'manual');
248
        $generator->enrol_user($user2->id, $course->id, $roleid, 'manual');
249
        $generator->enrol_user($USER->id, $course->id, $roleid, 'manual');
250
 
251
        // call as admin and receive all possible fields.
252
        $this->setAdminUser();
253
 
254
        $fieldstosearch = array('id', 'idnumber', 'username', 'email');
255
 
256
        foreach ($fieldstosearch as $fieldtosearch) {
257
 
258
            // Call the external function.
259
            $returnedusers = core_user_external::get_users_by_field($fieldtosearch,
260
                        array($USER->{$fieldtosearch}, $user1->{$fieldtosearch}, $user2->{$fieldtosearch}));
261
            $returnedusers = external_api::clean_returnvalue(core_user_external::get_users_by_field_returns(), $returnedusers);
262
 
263
            // Expected result differ following the searched field
264
            // Admin user in the PHPunit framework doesn't have an idnumber.
265
            if ($fieldtosearch == 'idnumber') {
266
                $expectedreturnedusers = 2;
267
            } else {
268
                $expectedreturnedusers = 3;
269
            }
270
 
271
            // Check we retrieve the good total number of enrolled users + no error on capability.
272
            $this->assertEquals($expectedreturnedusers, count($returnedusers));
273
 
274
            foreach($returnedusers as $returneduser) {
275
                $generateduser = ($returneduser['id'] == $USER->id) ?
276
                                    $USER : $generatedusers[$returneduser['id']];
277
                $this->assertEquals($generateduser->username, $returneduser['username']);
278
                if (!empty($generateduser->idnumber)) {
279
                    $this->assertEquals($generateduser->idnumber, $returneduser['idnumber']);
280
                }
281
                $this->assertEquals($generateduser->firstname, $returneduser['firstname']);
282
                $this->assertEquals($generateduser->lastname, $returneduser['lastname']);
283
                if ($generateduser->email != $USER->email) { //don't check the tmp modified $USER email
284
                    $this->assertEquals($generateduser->email, $returneduser['email']);
285
                }
286
                if (!empty($generateduser->address)) {
287
                    $this->assertEquals($generateduser->address, $returneduser['address']);
288
                }
289
                if (!empty($generateduser->phone1)) {
290
                    $this->assertEquals($generateduser->phone1, $returneduser['phone1']);
291
                }
292
                if (!empty($generateduser->phone2)) {
293
                    $this->assertEquals($generateduser->phone2, $returneduser['phone2']);
294
                }
295
                if (!empty($generateduser->department)) {
296
                    $this->assertEquals($generateduser->department, $returneduser['department']);
297
                }
298
                if (!empty($generateduser->institution)) {
299
                    $this->assertEquals($generateduser->institution, $returneduser['institution']);
300
                }
301
                if (!empty($generateduser->description)) {
302
                    $this->assertEquals($generateduser->description, $returneduser['description']);
303
                }
304
                if (!empty($generateduser->descriptionformat) and isset($returneduser['descriptionformat'])) {
305
                    $this->assertEquals($generateduser->descriptionformat, $returneduser['descriptionformat']);
306
                }
307
                if (!empty($generateduser->city)) {
308
                    $this->assertEquals($generateduser->city, $returneduser['city']);
309
                }
310
                if (!empty($generateduser->country)) {
311
                    $this->assertEquals($generateduser->country, $returneduser['country']);
312
                }
313
                if (!empty($CFG->usetags) and !empty($generateduser->interests)) {
314
                    $this->assertEquals(implode(', ', $generateduser->interests), $returneduser['interests']);
315
                }
316
                // Default language and no theme were used for the user.
317
                $this->assertEquals($CFG->lang, $returneduser['lang']);
318
                $this->assertEquals($generateduser->trackforums, $returneduser['trackforums']);
319
                $this->assertEmpty($returneduser['theme']);
320
 
321
                if ($returneduser['id'] == $user1->id) {
322
                    $this->assertCount(1, $returneduser['customfields']);
323
                    $dbvalue = explode('\n', $statuses)[2];
324
                    $this->assertEquals($dbvalue, $returneduser['customfields'][0]['value']);
325
                    $this->assertEquals('Employment status', $returneduser['customfields'][0]['name']);
326
                    $this->assertEquals('Other', $returneduser['customfields'][0]['displayvalue']);
327
                }
328
            }
329
        }
330
 
331
        // Test that no result are returned for search by username if we are not admin
332
        $this->setGuestUser();
333
 
334
        // Call the external function.
335
        $returnedusers = core_user_external::get_users_by_field('username',
336
                    array($USER->username, $user1->username, $user2->username));
337
        $returnedusers = external_api::clean_returnvalue(core_user_external::get_users_by_field_returns(), $returnedusers);
338
 
339
        // Only the own $USER username should be returned
340
        $this->assertEquals(1, count($returnedusers));
341
 
342
        // And finally test as one of the enrolled users.
343
        $this->setUser($user1);
344
 
345
        // Call the external function.
346
        $returnedusers = core_user_external::get_users_by_field('username',
347
            array($USER->username, $user1->username, $user2->username));
348
        $returnedusers = external_api::clean_returnvalue(core_user_external::get_users_by_field_returns(), $returnedusers);
349
 
350
        // Only the own $USER username should be returned still.
351
        $this->assertEquals(1, count($returnedusers));
352
    }
353
 
354
    public function get_course_user_profiles_setup($capability) {
355
        global $USER, $CFG;
356
 
357
        $this->resetAfterTest(true);
358
 
359
        $return = new \stdClass();
360
 
361
        $generator = self::getDataGenerator();
362
 
363
        // Create complex user profile field supporting multi-lang.
364
        filter_set_global_state('multilang', TEXTFILTER_ON);
1441 ariadna 365
        filter_set_applies_to_strings('multilang', true);
366
 
1 efrain 367
        $name = '<span lang="en" class="multilang">Employment status</span>' .
368
            '<span lang="es" class="multilang">Estado de Empleo</span>';
369
        $statuses = 'UE\nSE\n<span lang="en" class="multilang">Other</span><span lang="es" class="multilang">Otro</span>';
370
        $generator->create_custom_profile_field(
371
            [
372
                'datatype' => 'menu',
373
                'shortname' => 'employmentstatus',
374
                'name' => $name,
375
                'param1' => $statuses,
376
            ]
377
        );
378
 
379
        // Create the course and fetch its context.
380
        $return->course = self::getDataGenerator()->create_course();
381
        $return->user1 = array(
382
            'username' => 'usernametest1',
383
            'idnumber' => 'idnumbertest1',
384
            'firstname' => 'First Name User Test 1',
385
            'lastname' => 'Last Name User Test 1',
386
            'email' => 'usertest1@example.com',
387
            'address' => '2 Test Street Perth 6000 WA',
388
            'phone1' => '01010101010',
389
            'phone2' => '02020203',
390
            'department' => 'Department of user 1',
391
            'institution' => 'Institution of user 1',
392
            'description' => 'This is a description for user 1',
393
            'descriptionformat' => FORMAT_MOODLE,
394
            'city' => 'Perth',
395
            'country' => 'AU',
396
            'profile_field_employmentstatus' => explode('\n', $statuses)[2],
397
        );
398
        $return->user1 = self::getDataGenerator()->create_user($return->user1);
399
        if (!empty($CFG->usetags)) {
400
            require_once($CFG->dirroot . '/user/editlib.php');
401
            $return->user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking');
402
            useredit_update_interests($return->user1, $return->user1->interests);
403
        }
404
        $return->user2 = self::getDataGenerator()->create_user();
405
 
406
        $context = \context_course::instance($return->course->id);
407
        $return->roleid = $this->assignUserCapability($capability, $context->id);
408
 
409
        // Enrol the users in the course.
410
        $this->getDataGenerator()->enrol_user($return->user1->id, $return->course->id, $return->roleid, 'manual');
411
        $this->getDataGenerator()->enrol_user($return->user2->id, $return->course->id, $return->roleid, 'manual');
412
        $this->getDataGenerator()->enrol_user($USER->id, $return->course->id, $return->roleid, 'manual');
413
 
414
        $group1 = $this->getDataGenerator()->create_group(['courseid' => $return->course->id, 'name' => 'G1']);
415
        $group2 = $this->getDataGenerator()->create_group(['courseid' => $return->course->id, 'name' => 'G2']);
416
 
417
        groups_add_member($group1->id, $return->user1->id);
418
        groups_add_member($group2->id, $return->user2->id);
419
 
420
        return $return;
421
    }
422
 
423
    /**
424
     * Test get_course_user_profiles
425
     */
11 efrain 426
    public function test_get_course_user_profiles(): void {
1 efrain 427
        global $USER, $CFG;
428
 
429
        $this->resetAfterTest(true);
430
 
431
        $data = $this->get_course_user_profiles_setup('moodle/user:viewdetails');
432
 
433
        // Call the external function.
434
        $enrolledusers = core_user_external::get_course_user_profiles(array(
435
                    array('userid' => $USER->id, 'courseid' => $data->course->id)));
436
 
437
        // We need to execute the return values cleaning process to simulate the web service server.
438
        $enrolledusers = external_api::clean_returnvalue(core_user_external::get_course_user_profiles_returns(), $enrolledusers);
439
 
440
        // Check we retrieve the good total number of enrolled users + no error on capability.
441
        $this->assertEquals(1, count($enrolledusers));
442
    }
443
 
11 efrain 444
    public function test_get_user_course_profile_as_admin(): void {
1 efrain 445
        global $USER, $CFG;
446
 
447
        global $USER, $CFG;
448
 
449
        $this->resetAfterTest(true);
450
 
451
        $data = $this->get_course_user_profiles_setup('moodle/user:viewdetails');
452
 
453
        // Do the same call as admin to receive all possible fields.
454
        $this->setAdminUser();
455
        $USER->email = "admin@example.com";
456
 
457
        // Call the external function.
458
        $enrolledusers = core_user_external::get_course_user_profiles(array(
459
            array('userid' => $data->user1->id, 'courseid' => $data->course->id)));
460
 
461
        // We need to execute the return values cleaning process to simulate the web service server.
462
        $enrolledusers = external_api::clean_returnvalue(core_user_external::get_course_user_profiles_returns(), $enrolledusers);
463
        // Check we get the requested user and that is in a group.
464
        $this->assertCount(1, $enrolledusers);
465
        $this->assertCount(1, $enrolledusers[0]['groups']);
466
 
467
        foreach($enrolledusers as $enrolleduser) {
468
            if ($enrolleduser['username'] == $data->user1->username) {
469
                $this->assertEquals($data->user1->idnumber, $enrolleduser['idnumber']);
470
                $this->assertEquals($data->user1->firstname, $enrolleduser['firstname']);
471
                $this->assertEquals($data->user1->lastname, $enrolleduser['lastname']);
472
                $this->assertEquals($data->user1->email, $enrolleduser['email']);
473
                $this->assertEquals($data->user1->address, $enrolleduser['address']);
474
                $this->assertEquals($data->user1->phone1, $enrolleduser['phone1']);
475
                $this->assertEquals($data->user1->phone2, $enrolleduser['phone2']);
476
                $this->assertEquals($data->user1->department, $enrolleduser['department']);
477
                $this->assertEquals($data->user1->institution, $enrolleduser['institution']);
478
                $this->assertEquals($data->user1->description, $enrolleduser['description']);
479
                $this->assertEquals(FORMAT_HTML, $enrolleduser['descriptionformat']);
480
                $this->assertEquals($data->user1->city, $enrolleduser['city']);
481
                $this->assertEquals($data->user1->country, $enrolleduser['country']);
482
                // Default language was used for the user.
483
                $this->assertEquals($CFG->lang, $enrolleduser['lang']);
484
                $this->assertEquals('Employment status', $enrolleduser['customfields'][0]['name']);
485
                $this->assertEquals('Other', $enrolleduser['customfields'][0]['displayvalue']);
486
 
487
                if (!empty($CFG->usetags)) {
488
                    $this->assertEquals(implode(', ', $data->user1->interests), $enrolleduser['interests']);
489
                }
490
            }
491
        }
492
    }
493
 
494
    /**
495
     * Test create_users
496
     */
11 efrain 497
    public function test_create_users(): void {
1 efrain 498
        global $DB;
499
 
500
        $this->resetAfterTest(true);
501
 
1441 ariadna 502
        $user1 = [
1 efrain 503
            'username' => 'usernametest1',
504
            'password' => 'Moodle2012!',
505
            'idnumber' => 'idnumbertest1',
506
            'firstname' => 'First Name User Test 1',
507
            'lastname' => 'Last Name User Test 1',
508
            'middlename' => 'Middle Name User Test 1',
509
            'lastnamephonetic' => '最後のお名前のテスト一号',
510
            'firstnamephonetic' => 'お名前のテスト一号',
511
            'alternatename' => 'Alternate Name User Test 1',
512
            'email' => 'usertest1@example.com',
513
            'description' => 'This is a description for user 1',
514
            'city' => 'Perth',
515
            'country' => 'AU',
1441 ariadna 516
            'preferences' => [
517
                [
1 efrain 518
                    'type' => 'htmleditor',
1441 ariadna 519
                    'value' => 'tiny',
520
                ],
521
                [
1 efrain 522
                    'type' => 'invalidpreference',
1441 ariadna 523
                    'value' => 'abcd',
524
                ],
1 efrain 525
            ],
526
            'department' => 'College of Science',
527
            'institution' => 'National Institute of Physics',
528
            'phone1' => '01 2345 6789',
529
            'maildisplay' => 1,
1441 ariadna 530
            'interests' => 'badminton, basketball, cooking,  ',
531
        ];
1 efrain 532
 
533
        // User with an authentication method done externally.
534
        $user2 = array(
535
            'username' => 'usernametest2',
536
            'firstname' => 'First Name User Test 2',
537
            'lastname' => 'Last Name User Test 2',
538
            'email' => 'usertest2@example.com',
539
            'auth' => 'oauth2'
540
        );
541
 
542
        $context = \context_system::instance();
543
        $roleid = $this->assignUserCapability('moodle/user:create', $context->id);
544
        $this->assignUserCapability('moodle/user:editprofile', $context->id, $roleid);
545
 
546
        // Call the external function.
547
        $createdusers = core_user_external::create_users(array($user1, $user2));
548
 
549
        // We need to execute the return values cleaning process to simulate the web service server.
550
        $createdusers = external_api::clean_returnvalue(core_user_external::create_users_returns(), $createdusers);
551
 
552
        // Check we retrieve the good total number of created users + no error on capability.
553
        $this->assertCount(2, $createdusers);
554
 
555
        foreach($createdusers as $createduser) {
556
            $dbuser = $DB->get_record('user', array('id' => $createduser['id']));
557
 
558
            if ($createduser['username'] === $user1['username']) {
559
                $usertotest = $user1;
1441 ariadna 560
                $this->assertEquals('tiny', get_user_preferences('htmleditor', null, $dbuser));
1 efrain 561
                $this->assertEquals(null, get_user_preferences('invalidpreference', null, $dbuser));
562
                // Confirm user interests have been saved.
563
                $interests = \core_tag_tag::get_item_tags_array('core', 'user', $createduser['id'],
564
                        \core_tag_tag::BOTH_STANDARD_AND_NOT, 0, false);
565
                // There should be 3 user interests.
566
                $this->assertCount(3, $interests);
567
 
568
            } else if ($createduser['username'] === $user2['username']) {
569
                $usertotest = $user2;
570
            }
571
 
572
            foreach ($dbuser as $property => $value) {
573
                if ($property === 'password') {
574
                    if ($usertotest === $user2) {
575
                        // External auth mechanisms don't store password in the user table.
576
                        $this->assertEquals(AUTH_PASSWORD_NOT_CACHED, $value);
577
                    } else {
578
                        // Skip hashed passwords.
579
                        continue;
580
                    }
581
                }
582
                // Confirm that the values match.
583
                if (isset($usertotest[$property])) {
584
                    $this->assertEquals($usertotest[$property], $value);
585
                }
586
            }
587
        }
588
 
589
        // Call without required capability
590
        $this->unassignUserCapability('moodle/user:create', $context->id, $roleid);
591
        $this->expectException('required_capability_exception');
592
        core_user_external::create_users(array($user1));
593
    }
594
 
595
    /**
596
     * Test create_users with password and createpassword parameter not set.
597
     */
11 efrain 598
    public function test_create_users_empty_password(): void {
1 efrain 599
        $this->resetAfterTest();
600
        $this->setAdminUser();
601
 
602
        $user = [
603
            'username' => 'usernametest1',
604
            'firstname' => 'First Name User Test 1',
605
            'lastname' => 'Last Name User Test 1',
606
            'email' => 'usertest1@example.com',
607
        ];
608
 
609
        // This should throw an exception because either password or createpassword param must be passed for auth_manual.
610
        $this->expectException(\invalid_parameter_exception::class);
611
        core_user_external::create_users([$user]);
612
    }
613
 
614
    /**
615
     * Data provider for \core_user_externallib_testcase::test_create_users_with_same_emails().
616
     */
1441 ariadna 617
    public static function create_users_provider_with_same_emails(): array {
1 efrain 618
        return [
619
            'Same emails allowed, same case' => [
620
                1, false
621
            ],
622
            'Same emails allowed, different case' => [
623
                1, true
624
            ],
625
            'Same emails disallowed, same case' => [
626
                0, false
627
            ],
628
            'Same emails disallowed, different case' => [
629
                0, true
630
            ],
631
        ];
632
    }
633
 
634
    /**
635
     * Test for \core_user_external::create_users() when user using the same email addresses are being created.
636
     *
637
     * @dataProvider create_users_provider_with_same_emails
638
     * @param int $sameemailallowed The value to set for $CFG->allowaccountssameemail.
639
     * @param boolean $differentcase Whether to user a different case for the other user.
640
     */
11 efrain 641
    public function test_create_users_with_same_emails($sameemailallowed, $differentcase): void {
1 efrain 642
        global $DB;
643
 
644
        $this->resetAfterTest();
645
        $this->setAdminUser();
646
 
647
        // Allow multiple users with the same email address.
648
        set_config('allowaccountssameemail', $sameemailallowed);
649
        $users = [
650
            [
651
                'username' => 's1',
652
                'firstname' => 'Johnny',
653
                'lastname' => 'Bravo',
654
                'email' => 's1@example.com',
655
                'password' => 'Passw0rd!'
656
            ],
657
            [
658
                'username' => 's2',
659
                'firstname' => 'John',
660
                'lastname' => 'Doe',
661
                'email' => $differentcase ? 'S1@EXAMPLE.COM' : 's1@example.com',
662
                'password' => 'Passw0rd!'
663
            ],
664
        ];
665
 
666
        if (!$sameemailallowed) {
667
            // This should throw an exception when $CFG->allowaccountssameemail is empty.
668
            $this->expectException(\invalid_parameter_exception::class);
669
        }
670
 
671
        // Create our users.
672
        core_user_external::create_users($users);
673
 
674
        // Confirm that the users have been created.
675
        list($insql, $params) = $DB->get_in_or_equal(['s1', 's2']);
676
        $this->assertEquals(2, $DB->count_records_select('user', 'username ' . $insql, $params));
677
    }
678
 
679
    /**
680
     * Test create_users with invalid parameters
681
     *
682
     * @dataProvider data_create_users_invalid_parameter
683
     * @param array $data User data to attempt to register.
684
     * @param string $expectmessage Expected exception message.
685
     */
11 efrain 686
    public function test_create_users_invalid_parameter(array $data, $expectmessage): void {
1 efrain 687
        global $USER, $CFG, $DB;
688
 
689
        $this->resetAfterTest(true);
690
        $this->assignUserCapability('moodle/user:create', SYSCONTEXTID);
691
 
692
        $this->expectException('invalid_parameter_exception');
693
        $this->expectExceptionMessage($expectmessage);
694
 
695
        core_user_external::create_users(array($data));
696
    }
697
 
698
    /**
699
     * Data provider for {@see self::test_create_users_invalid_parameter()}.
700
     *
701
     * @return array
702
     */
1441 ariadna 703
    public static function data_create_users_invalid_parameter(): array {
1 efrain 704
        return [
705
            'blank_username' => [
706
                'data' => [
707
                    'username' => '',
708
                    'firstname' => 'Foo',
709
                    'lastname' => 'Bar',
710
                    'email' => 'foobar@example.com',
711
                    'createpassword' => 1,
712
                ],
713
                'expectmessage' => 'The field username cannot be blank',
714
            ],
715
            'blank_firtname' => [
716
                'data' => [
717
                    'username' => 'foobar',
718
                    'firstname' => "\t \n",
719
                    'lastname' => 'Bar',
720
                    'email' => 'foobar@example.com',
721
                    'createpassword' => 1,
722
                ],
723
                'expectmessage' => 'The field firstname cannot be blank',
724
            ],
725
            'blank_lastname' => [
726
                'data' => [
727
                    'username' => 'foobar',
728
                    'firstname' => '0',
729
                    'lastname' => '   ',
730
                    'email' => 'foobar@example.com',
731
                    'createpassword' => 1,
732
                ],
733
                'expectmessage' => 'The field lastname cannot be blank',
734
            ],
735
            'invalid_email' => [
736
                'data' => [
737
                    'username' => 'foobar',
738
                    'firstname' => 'Foo',
739
                    'lastname' => 'Bar',
740
                    'email' => '@foobar',
741
                    'createpassword' => 1,
742
                ],
743
                'expectmessage' => 'Email address is invalid',
744
            ],
745
            'missing_password' => [
746
                'data' => [
747
                    'username' => 'foobar',
748
                    'firstname' => 'Foo',
749
                    'lastname' => 'Bar',
750
                    'email' => 'foobar@example.com',
751
                ],
752
                'expectmessage' => 'Invalid password: you must provide a password, or set createpassword',
753
            ],
754
        ];
755
    }
756
 
757
    /**
758
     * Test delete_users
759
     */
11 efrain 760
    public function test_delete_users(): void {
1 efrain 761
        global $USER, $CFG, $DB;
762
 
763
        $this->resetAfterTest(true);
764
 
765
        $user1 = self::getDataGenerator()->create_user();
766
        $user2 = self::getDataGenerator()->create_user();
767
 
768
        // Check the users were correctly created.
769
        $this->assertEquals(2, $DB->count_records_select('user', 'deleted = 0 AND (id = :userid1 OR id = :userid2)',
770
                array('userid1' => $user1->id, 'userid2' => $user2->id)));
771
 
772
        $context = \context_system::instance();
773
        $roleid = $this->assignUserCapability('moodle/user:delete', $context->id);
774
 
775
        // Call the external function.
776
        core_user_external::delete_users(array($user1->id, $user2->id));
777
 
778
        // Check we retrieve no users + no error on capability.
779
        $this->assertEquals(0, $DB->count_records_select('user', 'deleted = 0 AND (id = :userid1 OR id = :userid2)',
780
                array('userid1' => $user1->id, 'userid2' => $user2->id)));
781
 
782
        // Call without required capability.
783
        $this->unassignUserCapability('moodle/user:delete', $context->id, $roleid);
784
        $this->expectException('required_capability_exception');
785
        core_user_external::delete_users(array($user1->id, $user2->id));
786
    }
787
 
788
    /**
789
     * Test update_users
790
     */
11 efrain 791
    public function test_update_users(): void {
1 efrain 792
        global $USER, $CFG, $DB;
793
 
794
        $this->resetAfterTest(true);
795
        $this->preventResetByRollback();
796
 
797
        $wsuser = self::getDataGenerator()->create_user();
798
        self::setUser($wsuser);
799
 
800
        $context = \context_user::instance($USER->id);
801
        $contextid = $context->id;
802
        $filename = "reddot.png";
803
        $filecontent = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38"
804
            . "GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
805
 
806
        // Call the files api to create a file.
807
        $draftfile = core_files_external::upload($contextid, 'user', 'draft', 0, '/',
808
                $filename, $filecontent, null, null);
809
        $draftfile = external_api::clean_returnvalue(core_files_external::upload_returns(), $draftfile);
810
 
811
        $draftid = $draftfile['itemid'];
812
 
813
        $user1 = self::getDataGenerator()->create_user();
814
 
1441 ariadna 815
        $user1 = [
1 efrain 816
            'id' => $user1->id,
817
            'username' => 'usernametest1',
818
            'password' => 'Moodle2012!',
819
            'idnumber' => 'idnumbertest1',
820
            'firstname' => 'First Name User Test 1',
821
            'lastname' => 'Last Name User Test 1',
822
            'middlename' => 'Middle Name User Test 1',
823
            'lastnamephonetic' => '最後のお名前のテスト一号',
824
            'firstnamephonetic' => 'お名前のテスト一号',
825
            'alternatename' => 'Alternate Name User Test 1',
826
            'email' => 'usertest1@example.com',
827
            'description' => 'This is a description for user 1',
828
            'city' => 'Perth',
829
            'userpicture' => $draftid,
830
            'country' => 'AU',
1441 ariadna 831
            'preferences' => [
832
                [
1 efrain 833
                    'type' => 'htmleditor',
1441 ariadna 834
                    'value' => 'textarea',
835
                ],
836
                [
1 efrain 837
                    'type' => 'invialidpreference',
1441 ariadna 838
                    'value' => 'abcd',
839
                ],
1 efrain 840
            ],
841
            'department' => 'College of Science',
842
            'institution' => 'National Institute of Physics',
843
            'phone1' => '01 2345 6789',
844
            'maildisplay' => 1,
1441 ariadna 845
            'interests' => 'badminton, basketball, cooking,  ',
846
        ];
1 efrain 847
 
848
        $context = \context_system::instance();
849
        $roleid = $this->assignUserCapability('moodle/user:update', $context->id);
850
        $this->assignUserCapability('moodle/user:editprofile', $context->id, $roleid);
851
 
852
        // Check we can't update deleted users, guest users, site admin.
853
        $user2 = $user3 = $user4 = $user1;
854
        $user2['id'] = $CFG->siteguest;
855
 
856
        $siteadmins = explode(',', $CFG->siteadmins);
857
        $user3['id'] = array_shift($siteadmins);
858
 
859
        $userdeleted = self::getDataGenerator()->create_user();
860
        $user4['id'] = $userdeleted->id;
861
        user_delete_user($userdeleted);
862
 
863
        $user5 = self::getDataGenerator()->create_user();
864
        $user5 = array('id' => $user5->id, 'email' => $user5->email);
865
 
866
        // Call the external function.
867
        $returnvalue = core_user_external::update_users(array($user1, $user2, $user3, $user4));
868
        $returnvalue = external_api::clean_returnvalue(core_user_external::update_users_returns(), $returnvalue);
869
 
870
        // Check warnings.
871
        $this->assertEquals($user2['id'], $returnvalue['warnings'][0]['itemid']); // Guest user.
872
        $this->assertEquals('usernotupdatedguest', $returnvalue['warnings'][0]['warningcode']);
873
        $this->assertEquals($user3['id'], $returnvalue['warnings'][1]['itemid']); // Admin user.
874
        $this->assertEquals('usernotupdatedadmin', $returnvalue['warnings'][1]['warningcode']);
875
        $this->assertEquals($user4['id'], $returnvalue['warnings'][2]['itemid']); // Deleted user.
876
        $this->assertEquals('usernotupdateddeleted', $returnvalue['warnings'][2]['warningcode']);
877
 
878
        $dbuser2 = $DB->get_record('user', array('id' => $user2['id']));
879
        $this->assertNotEquals($dbuser2->username, $user2['username']);
880
        $dbuser3 = $DB->get_record('user', array('id' => $user3['id']));
881
        $this->assertNotEquals($dbuser3->username, $user3['username']);
882
        $dbuser4 = $DB->get_record('user', array('id' => $user4['id']));
883
        $this->assertNotEquals($dbuser4->username, $user4['username']);
884
 
885
        $dbuser = $DB->get_record('user', array('id' => $user1['id']));
886
        $this->assertEquals($dbuser->username, $user1['username']);
887
        $this->assertEquals($dbuser->idnumber, $user1['idnumber']);
888
        $this->assertEquals($dbuser->firstname, $user1['firstname']);
889
        $this->assertEquals($dbuser->lastname, $user1['lastname']);
890
        $this->assertEquals($dbuser->email, $user1['email']);
891
        $this->assertEquals($dbuser->description, $user1['description']);
892
        $this->assertEquals($dbuser->city, $user1['city']);
893
        $this->assertEquals($dbuser->country, $user1['country']);
894
        $this->assertNotEquals(0, $dbuser->picture, 'Picture must be set to the new icon itemid for this user');
895
        $this->assertEquals($dbuser->department, $user1['department']);
896
        $this->assertEquals($dbuser->institution, $user1['institution']);
897
        $this->assertEquals($dbuser->phone1, $user1['phone1']);
898
        $this->assertEquals($dbuser->maildisplay, $user1['maildisplay']);
1441 ariadna 899
        $this->assertEquals('textarea', get_user_preferences('htmleditor', null, $dbuser));
1 efrain 900
        $this->assertEquals(null, get_user_preferences('invalidpreference', null, $dbuser));
901
 
902
        // Confirm user interests have been saved.
903
        $interests = \core_tag_tag::get_item_tags_array('core', 'user', $user1['id'], \core_tag_tag::BOTH_STANDARD_AND_NOT, 0, false);
904
        // There should be 3 user interests.
905
        $this->assertCount(3, $interests);
906
 
907
        // Confirm no picture change when parameter is not supplied.
908
        unset($user1['userpicture']);
909
        core_user_external::update_users(array($user1));
910
        $dbusernopic = $DB->get_record('user', array('id' => $user1['id']));
911
        $this->assertEquals($dbuser->picture, $dbusernopic->picture, 'Picture not change without the parameter.');
912
 
913
        // Confirm delete of picture deletes the picture from the user record.
914
        $user1['userpicture'] = 0;
915
        core_user_external::update_users(array($user1));
916
        $dbuserdelpic = $DB->get_record('user', array('id' => $user1['id']));
917
        $this->assertEquals(0, $dbuserdelpic->picture, 'Picture must be deleted when sent as 0.');
918
 
919
        // Updating user with an invalid email.
920
        $user5['email'] = 'bogus';
921
        $returnvalue = core_user_external::update_users(array($user5));
922
        $returnvalue = external_api::clean_returnvalue(core_user_external::update_users_returns(), $returnvalue);
923
        $this->assertEquals('useremailinvalid', $returnvalue['warnings'][0]['warningcode']);
924
        $this->assertStringContainsString('Invalid email address',
925
            $returnvalue['warnings'][0]['message']);
926
 
927
        // Updating user with a duplicate email.
928
        $user5['email'] = $user1['email'];
929
        $returnvalue = core_user_external::update_users(array($user1, $user5));
930
        $returnvalue = external_api::clean_returnvalue(core_user_external::update_users_returns(), $returnvalue);
931
        $this->assertEquals('useremailduplicate', $returnvalue['warnings'][0]['warningcode']);
932
        $this->assertStringContainsString('Duplicate email address',
933
                $returnvalue['warnings'][0]['message']);
934
 
935
        // Updating a user that does not exist.
936
        $user5['id'] = -1;
937
        $returnvalue = core_user_external::update_users(array($user5));
938
        $returnvalue = external_api::clean_returnvalue(core_user_external::update_users_returns(), $returnvalue);
939
        $this->assertEquals('invaliduserid', $returnvalue['warnings'][0]['warningcode']);
940
        $this->assertStringContainsString('Invalid user ID',
941
                $returnvalue['warnings'][0]['message']);
942
 
943
        // Updating a remote user.
944
        $user1['mnethostid'] = 5;
945
        user_update_user($user1); // Update user not using webservice.
946
        unset($user1['mnethostid']); // The mnet host ID field is not in the allowed field list for the webservice.
947
        $returnvalue = core_user_external::update_users(array($user1));
948
        $returnvalue = external_api::clean_returnvalue(core_user_external::update_users_returns(), $returnvalue);
949
        $this->assertEquals('usernotupdatedremote', $returnvalue['warnings'][0]['warningcode']);
950
        $this->assertStringContainsString('User is a remote user',
951
                $returnvalue['warnings'][0]['message']);
952
 
953
        // Call without required capability.
954
        $this->unassignUserCapability('moodle/user:update', $context->id, $roleid);
955
        $this->expectException('required_capability_exception');
956
        core_user_external::update_users(array($user1));
957
    }
958
 
959
    /**
960
     * Data provider for testing \core_user_external::update_users() for users with same emails
961
     *
962
     * @return array
963
     */
1441 ariadna 964
    public static function users_with_same_emails(): array {
1 efrain 965
        return [
966
            'Same emails not allowed: Update name using exactly the same email' => [
967
                0, 'John', 's1@example.com', 'Johnny', 's1@example.com', false, true
968
            ],
969
            'Same emails not allowed: Update using someone else\'s email' => [
970
                0, 'John', 's1@example.com', 'Johnny', 's2@example.com', true, false
971
            ],
972
            'Same emails allowed: Update using someone else\'s email' => [
973
                1, 'John', 's1@example.com', 'Johnny', 's2@example.com', true, true
974
            ],
975
            'Same emails not allowed: Update using same email but with different case' => [
976
                0, 'John', 's1@example.com', 'Johnny', 'S1@EXAMPLE.COM', false, true
977
            ],
978
            'Same emails not allowed: Update using another user\'s email similar to user but with different case' => [
979
                0, 'John', 's1@example.com', 'Johnny', 'S1@EXAMPLE.COM', true, false
980
            ],
981
            'Same emails allowed: Update using another user\'s email similar to user but with different case' => [
982
                1, 'John', 's1@example.com', 'Johnny', 'S1@EXAMPLE.COM', true, true
983
            ],
984
        ];
985
    }
986
 
987
    /**
988
     * Test update_users using similar emails with varying cases.
989
     *
990
     * @dataProvider users_with_same_emails
991
     * @param boolean $allowsameemail The value to set for $CFG->allowaccountssameemail.
992
     * @param string $currentname The user's current name.
993
     * @param string $currentemail The user's current email.
994
     * @param string $newname The user's new name.
995
     * @param string $newemail The user's new email.
996
     * @param boolean $withanotheruser Whether to create another user that has the same email as the target user's new email.
997
     * @param boolean $successexpected Whether we expect that the target user's email/name will be updated.
998
     */
999
    public function test_update_users_emails_with_different_cases($allowsameemail, $currentname, $currentemail,
11 efrain 1000
                                                                  $newname, $newemail, $withanotheruser, $successexpected): void {
1 efrain 1001
        global $DB;
1002
 
1003
        $this->resetAfterTest();
1004
        $this->setAdminUser();
1005
 
1006
        // Set the value for $CFG->allowaccountssameemail.
1007
        set_config('allowaccountssameemail', $allowsameemail);
1008
 
1009
        $generator = self::getDataGenerator();
1010
 
1011
        // Create the user that we wish to update.
1012
        $usertoupdate = $generator->create_user(['email' => $currentemail, 'firstname' => $currentname]);
1013
 
1014
        if ($withanotheruser) {
1015
            // Create another user that has the same email as the new email that we'd like to update for our target user.
1016
            $generator->create_user(['email' => $newemail]);
1017
        }
1018
 
1019
        // Build the user update parameters.
1020
        $updateparams = [
1021
            'id' => $usertoupdate->id,
1022
            'email' => $newemail,
1023
            'firstname' => $newname
1024
        ];
1025
        // Let's try to update the user's information.
1026
        core_user_external::update_users([$updateparams]);
1027
 
1028
        // Fetch the updated user record.
1029
        $userrecord = $DB->get_record('user', ['id' => $usertoupdate->id], 'id, email, firstname');
1030
 
1031
        // If we expect the update to succeed, then the email/name would have been changed.
1032
        if ($successexpected) {
1033
            $expectedemail = $newemail;
1034
            $expectedname = $newname;
1035
        } else {
1036
            $expectedemail = $currentemail;
1037
            $expectedname = $currentname;
1038
        }
1039
        // Confirm that our expectations are met.
1040
        $this->assertEquals($expectedemail, $userrecord->email);
1041
        $this->assertEquals($expectedname, $userrecord->firstname);
1042
    }
1043
 
1044
    /**
1045
     * Test add_user_private_files
1046
     */
11 efrain 1047
    public function test_add_user_private_files(): void {
1 efrain 1048
        global $USER, $CFG, $DB;
1049
 
1050
        $this->resetAfterTest(true);
1051
 
1052
        $context = \context_system::instance();
1053
        $roleid = $this->assignUserCapability('moodle/user:manageownfiles', $context->id);
1054
 
1055
        $context = \context_user::instance($USER->id);
1056
        $contextid = $context->id;
1057
        $component = "user";
1058
        $filearea = "draft";
1059
        $itemid = 0;
1060
        $filepath = "/";
1061
        $filename = "Simple.txt";
1062
        $filecontent = base64_encode("Let us create a nice simple file");
1063
        $contextlevel = null;
1064
        $instanceid = null;
1065
        $browser = get_file_browser();
1066
 
1067
        // Call the files api to create a file.
1068
        $draftfile = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
1069
                                                 $filename, $filecontent, $contextlevel, $instanceid);
1070
        $draftfile = external_api::clean_returnvalue(core_files_external::upload_returns(), $draftfile);
1071
 
1072
        $draftid = $draftfile['itemid'];
1073
        // Make sure the file was created.
1074
        $file = $browser->get_file_info($context, $component, $filearea, $draftid, $filepath, $filename);
1075
        $this->assertNotEmpty($file);
1076
 
1077
        // Make sure the file does not exist in the user private files.
1078
        $file = $browser->get_file_info($context, $component, 'private', 0, $filepath, $filename);
1079
        $this->assertEmpty($file);
1080
 
1081
        // Call the external function.
1082
        core_user_external::add_user_private_files($draftid);
1083
 
1084
        // Make sure the file was added to the user private files.
1085
        $file = $browser->get_file_info($context, $component, 'private', 0, $filepath, $filename);
1086
        $this->assertNotEmpty($file);
1087
    }
1088
 
1089
 
1090
    /**
1091
     * Test add_user_private_files quota
1092
     */
11 efrain 1093
    public function test_add_user_private_files_quota(): void {
1 efrain 1094
        global $USER, $CFG, $DB;
1095
 
1096
        $this->resetAfterTest(true);
1097
 
1098
        $context = \context_system::instance();
1099
        $roleid = $this->assignUserCapability('moodle/user:manageownfiles', $context->id);
1100
 
1101
        $context = \context_user::instance($USER->id);
1102
        $contextid = $context->id;
1103
        $component = "user";
1104
        $filearea = "draft";
1105
        $itemid = 0;
1106
        $filepath = "/";
1107
        $filename = "Simple.txt";
1108
        $filecontent = base64_encode("Let us create a nice simple file");
1109
        $contextlevel = null;
1110
        $instanceid = null;
1111
        $browser = get_file_browser();
1112
 
1113
        // Call the files api to create a file.
1114
        $draftfile = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
1115
            $filename, $filecontent, $contextlevel, $instanceid);
1116
        $draftfile = external_api::clean_returnvalue(core_files_external::upload_returns(), $draftfile);
1117
        $draftid = $draftfile['itemid'];
1118
 
1119
        // Call the external function to add the file to private files.
1120
        core_user_external::add_user_private_files($draftid);
1121
 
1122
        // Force the quota so we are sure it won't be space to add the new file.
1123
        $fileareainfo = file_get_file_area_info($contextid, 'user', 'private');
1124
        $CFG->userquota = $fileareainfo['filesize_without_references'] + 1;
1125
 
1126
        // Generate a new draftitemid for the same testfile.
1127
        $draftfile = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
1128
            $filename, $filecontent, $contextlevel, $instanceid);
1129
        $draftid = $draftfile['itemid'];
1130
 
1131
        $this->expectException('moodle_exception');
1132
        $this->expectExceptionMessage(get_string('maxareabytes', 'error'));
1133
 
1134
        // Call the external function to include the new file.
1135
        core_user_external::add_user_private_files($draftid);
1136
    }
1137
 
1138
    /**
1139
     * Test add user device
1140
     */
11 efrain 1141
    public function test_add_user_device(): void {
1 efrain 1142
        global $USER, $CFG, $DB;
1143
 
1144
        $this->resetAfterTest(true);
1145
 
1146
        $device = array(
1147
                'appid' => 'com.moodle.moodlemobile',
1148
                'name' => 'occam',
1149
                'model' => 'Nexus 4',
1150
                'platform' => 'Android',
1151
                'version' => '4.2.2',
1152
                'pushid' => 'apushdkasdfj4835',
1153
                'uuid' => 'asdnfl348qlksfaasef859',
1154
                'publickey' => null,
1155
                );
1156
 
1157
        // Call the external function.
1158
        core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'],
1159
                                            $device['version'], $device['pushid'], $device['uuid']);
1160
 
1161
        $created = $DB->get_record('user_devices', array('pushid' => $device['pushid']));
1162
        $created = (array) $created;
1163
 
1164
        $this->assertEquals($device, array_intersect_key((array)$created, $device));
1165
 
1166
        // Test reuse the same pushid value.
1167
        $warnings = core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'],
1168
                                                        $device['version'], $device['pushid'], $device['uuid']);
1169
        // We need to execute the return values cleaning process to simulate the web service server.
1170
        $warnings = external_api::clean_returnvalue(core_user_external::add_user_device_returns(), $warnings);
1171
        $this->assertCount(1, $warnings);
1172
 
1173
        // Test update an existing device.
1174
        $device['pushid'] = 'different than before';
1175
        $device['publickey'] = 'MFsxCzAJBgNVBAYTAkZSMRMwEQYDVQQ';
1176
        $warnings = core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'],
1177
            $device['version'], $device['pushid'], $device['uuid'], $device['publickey']);
1178
        $warnings = external_api::clean_returnvalue(core_user_external::add_user_device_returns(), $warnings);
1179
 
1180
        $this->assertEquals(1, $DB->count_records('user_devices'));
1181
        $updated = $DB->get_record('user_devices', array('pushid' => $device['pushid']));
1182
        $this->assertEquals($device, array_intersect_key((array)$updated, $device));
1183
 
1184
        // Test creating a new device just changing the uuid.
1185
        $device['uuid'] = 'newuidforthesameuser';
1186
        $device['pushid'] = 'new different than before';
1187
        $warnings = core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'],
1188
                                                        $device['version'], $device['pushid'], $device['uuid']);
1189
        $warnings = external_api::clean_returnvalue(core_user_external::add_user_device_returns(), $warnings);
1190
        $this->assertEquals(2, $DB->count_records('user_devices'));
1191
    }
1192
 
1193
    /**
1194
     * Test remove user device
1195
     */
11 efrain 1196
    public function test_remove_user_device(): void {
1 efrain 1197
        global $USER, $CFG, $DB;
1198
 
1199
        $this->resetAfterTest(true);
1200
 
1201
        $device = array(
1202
                'appid' => 'com.moodle.moodlemobile',
1203
                'name' => 'occam',
1204
                'model' => 'Nexus 4',
1205
                'platform' => 'Android',
1206
                'version' => '4.2.2',
1207
                'pushid' => 'apushdkasdfj4835',
1208
                'uuid' => 'ABCDE3723ksdfhasfaasef859'
1209
                );
1210
 
1211
        // A device with the same properties except the appid and pushid.
1212
        $device2 = $device;
1213
        $device2['pushid'] = "0987654321";
1214
        $device2['appid'] = "other.app.com";
1215
 
1216
        $this->setAdminUser();
1217
        // Create a user device using the external API function.
1218
        core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'],
1219
                                            $device['version'], $device['pushid'], $device['uuid']);
1220
 
1221
        // Create the same device but for a different app.
1222
        core_user_external::add_user_device($device2['appid'], $device2['name'], $device2['model'], $device2['platform'],
1223
                                            $device2['version'], $device2['pushid'], $device2['uuid']);
1224
 
1225
        // Try to remove a device that does not exist.
1226
        $result = core_user_external::remove_user_device('1234567890');
1227
        $result = external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result);
1228
        $this->assertFalse($result['removed']);
1229
        $this->assertCount(1, $result['warnings']);
1230
 
1231
        // Try to remove a device that does not exist for an existing app.
1232
        $result = core_user_external::remove_user_device('1234567890', $device['appid']);
1233
        $result = external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result);
1234
        $this->assertFalse($result['removed']);
1235
        $this->assertCount(1, $result['warnings']);
1236
 
1237
        // Remove an existing device for an existing app. This will remove one of the two devices.
1238
        $result = core_user_external::remove_user_device($device['uuid'], $device['appid']);
1239
        $result = external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result);
1240
        $this->assertTrue($result['removed']);
1241
 
1242
        // Remove all the devices. This must remove the remaining device.
1243
        $result = core_user_external::remove_user_device($device['uuid']);
1244
        $result = external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result);
1245
        $this->assertTrue($result['removed']);
1246
    }
1247
 
1248
    /**
1249
     * Test get_user_preferences
1250
     */
11 efrain 1251
    public function test_get_user_preferences(): void {
1 efrain 1252
        $this->resetAfterTest(true);
1253
 
1254
        $user = self::getDataGenerator()->create_user();
1255
        set_user_preference('calendar_maxevents', 1, $user);
1256
        set_user_preference('some_random_text', 'text', $user);
1257
 
1258
        $this->setUser($user);
1259
 
1260
        $result = core_user_external::get_user_preferences();
1261
        $result = external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result);
1262
        $this->assertCount(0, $result['warnings']);
1263
        // Expect 3, _lastloaded is always returned.
1264
        $this->assertCount(3, $result['preferences']);
1265
 
1266
        foreach ($result['preferences'] as $pref) {
1267
            if ($pref['name'] === '_lastloaded') {
1268
                continue;
1269
            }
1270
            // Check we receive the expected preferences.
1271
            $this->assertEquals(get_user_preferences($pref['name']), $pref['value']);
1272
        }
1273
 
1274
        // Retrieve just one preference.
1275
        $result = core_user_external::get_user_preferences('some_random_text');
1276
        $result = external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result);
1277
        $this->assertCount(0, $result['warnings']);
1278
        $this->assertCount(1, $result['preferences']);
1279
        $this->assertEquals('text', $result['preferences'][0]['value']);
1280
 
1281
        // Retrieve non-existent preference.
1282
        $result = core_user_external::get_user_preferences('non_existent');
1283
        $result = external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result);
1284
        $this->assertCount(0, $result['warnings']);
1285
        $this->assertCount(1, $result['preferences']);
1286
        $this->assertEquals(null, $result['preferences'][0]['value']);
1287
 
1288
        // Check that as admin we can retrieve all the preferences for any user.
1289
        $this->setAdminUser();
1290
        $result = core_user_external::get_user_preferences('', $user->id);
1291
        $result = external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result);
1292
        $this->assertCount(0, $result['warnings']);
1293
        $this->assertCount(3, $result['preferences']);
1294
 
1295
        foreach ($result['preferences'] as $pref) {
1296
            if ($pref['name'] === '_lastloaded') {
1297
                continue;
1298
            }
1299
            // Check we receive the expected preferences.
1300
            $this->assertEquals(get_user_preferences($pref['name'], null, $user), $pref['value']);
1301
        }
1302
 
1303
        // Check that as a non admin user we cannot retrieve other users preferences.
1304
        $anotheruser = self::getDataGenerator()->create_user();
1305
        $this->setUser($anotheruser);
1306
 
1307
        $this->expectException('required_capability_exception');
1308
        $result = core_user_external::get_user_preferences('', $user->id);
1309
    }
1310
 
1311
    /**
1312
     * Test update_picture
1313
     */
11 efrain 1314
    public function test_update_picture(): void {
1 efrain 1315
        global $DB, $USER;
1316
 
1317
        $this->resetAfterTest(true);
1318
 
1319
        $user = self::getDataGenerator()->create_user();
1320
        self::setUser($user);
1321
 
1322
        $context = \context_user::instance($USER->id);
1323
        $contextid = $context->id;
1324
        $filename = "reddot.png";
1325
        $filecontent = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38"
1326
            . "GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
1327
 
1328
        // Call the files api to create a file.
1329
        $draftfile = core_files_external::upload($contextid, 'user', 'draft', 0, '/', $filename, $filecontent, null, null);
1330
        $draftid = $draftfile['itemid'];
1331
 
1332
        // Change user profile image.
1333
        $result = core_user_external::update_picture($draftid);
1334
        $result = external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result);
1335
        $picture = $DB->get_field('user', 'picture', array('id' => $user->id));
1336
        // The new revision is in the url for the user.
1337
        $this->assertStringContainsString($picture, $result['profileimageurl']);
1338
        // Check expected URL for serving the image.
1339
        $this->assertStringContainsString("/$contextid/user/icon", $result['profileimageurl']);
1340
 
1341
        // Delete image.
1342
        $result = core_user_external::update_picture(0, true);
1343
        $result = external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result);
1344
        $picture = $DB->get_field('user', 'picture', array('id' => $user->id));
1345
        // No picture.
1346
        $this->assertEquals(0, $picture);
1347
 
1348
        // Add again the user profile image (as admin).
1349
        $this->setAdminUser();
1350
 
1351
        $context = \context_user::instance($USER->id);
1352
        $admincontextid = $context->id;
1353
        $draftfile = core_files_external::upload($admincontextid, 'user', 'draft', 0, '/', $filename, $filecontent, null, null);
1354
        $draftid = $draftfile['itemid'];
1355
 
1356
        $result = core_user_external::update_picture($draftid, false, $user->id);
1357
        $result = external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result);
1358
        // The new revision is in the url for the user.
1359
        $picture = $DB->get_field('user', 'picture', array('id' => $user->id));
1360
        $this->assertStringContainsString($picture, $result['profileimageurl']);
1361
        $this->assertStringContainsString("/$contextid/user/icon", $result['profileimageurl']);
1362
    }
1363
 
1364
    /**
1365
     * Test update_picture disabled
1366
     */
11 efrain 1367
    public function test_update_picture_disabled(): void {
1 efrain 1368
        global $CFG;
1369
        $this->resetAfterTest(true);
1370
        $CFG->disableuserimages = true;
1371
 
1372
        $this->setAdminUser();
1373
        $this->expectException('moodle_exception');
1374
        core_user_external::update_picture(0);
1375
    }
1376
 
1377
    /**
1378
     * Test set_user_preferences
1379
     */
11 efrain 1380
    public function test_set_user_preferences_save(): void {
1 efrain 1381
        global $DB;
1382
        $this->resetAfterTest(true);
1383
 
1384
        $user1 = self::getDataGenerator()->create_user();
1385
        $user2 = self::getDataGenerator()->create_user();
1386
 
1387
        // Save users preferences.
1388
        $this->setAdminUser();
1389
        $preferences = array(
1390
            array(
1391
                'name' => 'htmleditor',
1441 ariadna 1392
                'value' => 'textarea',
1 efrain 1393
                'userid' => $user1->id,
1394
            ),
1395
            array(
1396
                'name' => 'htmleditor',
1397
                'value' => 'tiny',
1398
                'userid' => $user2->id,
1399
            )
1400
        );
1401
 
1402
        $result = core_user_external::set_user_preferences($preferences);
1403
        $result = external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result);
1404
        $this->assertCount(0, $result['warnings']);
1405
        $this->assertCount(2, $result['saved']);
1406
 
1407
        // Get preference from DB to avoid cache.
1441 ariadna 1408
        $this->assertEquals('textarea', $DB->get_field('user_preferences', 'value',
1 efrain 1409
            array('userid' => $user1->id, 'name' => 'htmleditor')));
1410
        $this->assertEquals('tiny', $DB->get_field('user_preferences', 'value',
1411
            array('userid' => $user2->id, 'name' => 'htmleditor')));
1412
    }
1413
 
1414
    /**
1415
     * Test set_user_preferences
1416
     */
11 efrain 1417
    public function test_set_user_preferences_save_invalid_pref(): void {
1 efrain 1418
        global $DB;
1419
        $this->resetAfterTest(true);
1420
 
1421
        $user1 = self::getDataGenerator()->create_user();
1422
 
1423
        // Save users preferences.
1424
        $this->setAdminUser();
1425
        $preferences = array(
1426
            array(
1427
                'name' => 'some_random_pref',
1428
                'value' => 'abc',
1429
                'userid' => $user1->id,
1430
            ),
1431
        );
1432
 
1433
        $result = core_user_external::set_user_preferences($preferences);
1434
        $result = external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result);
1435
        $this->assertCount(1, $result['warnings']);
1436
        $this->assertCount(0, $result['saved']);
1437
        $this->assertEquals('nopermission', $result['warnings'][0]['warningcode']);
1438
 
1439
        // Nothing was written to DB.
1440
        $this->assertEmpty($DB->count_records('user_preferences', array('name' => 'some_random_pref')));
1441
    }
1442
 
1443
    /**
1444
     * Test set_user_preferences for an invalid user
1445
     */
11 efrain 1446
    public function test_set_user_preferences_invalid_user(): void {
1 efrain 1447
        $this->resetAfterTest(true);
1448
 
1449
        $this->setAdminUser();
1450
        $preferences = array(
1451
            array(
1452
                'name' => 'calendar_maxevents',
1453
                'value' => 4,
1454
                'userid' => -2
1455
            )
1456
        );
1457
 
1458
        $result = core_user_external::set_user_preferences($preferences);
1459
        $result = external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result);
1460
        $this->assertCount(1, $result['warnings']);
1461
        $this->assertCount(0, $result['saved']);
1462
        $this->assertEquals('invaliduser', $result['warnings'][0]['warningcode']);
1463
        $this->assertEquals(-2, $result['warnings'][0]['itemid']);
1464
    }
1465
 
1466
    /**
1467
     * Test set_user_preferences using an invalid preference
1468
     */
11 efrain 1469
    public function test_set_user_preferences_invalid_preference(): void {
1 efrain 1470
        global $USER, $DB;
1471
 
1472
        $this->resetAfterTest(true);
1473
        // Create a very long value.
1474
        $this->setAdminUser();
1475
        $preferences = array(
1476
            array(
1477
                'name' => 'calendar_maxevents',
1478
                'value' => str_repeat('a', 1334),
1479
                'userid' => $USER->id
1480
            )
1481
        );
1482
 
1483
        $result = core_user_external::set_user_preferences($preferences);
1484
        $result = external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result);
1485
        $this->assertCount(0, $result['warnings']);
1486
        $this->assertCount(1, $result['saved']);
1487
        // Cleaned valud of the preference was saved.
1488
        $this->assertEquals(1, $DB->get_field('user_preferences', 'value',
1489
            array('userid' => $USER->id, 'name' => 'calendar_maxevents')));
1490
    }
1491
 
1492
    /**
1493
     * Test set_user_preferences for other user not being admin
1494
     */
11 efrain 1495
    public function test_set_user_preferences_capability(): void {
1 efrain 1496
        $this->resetAfterTest(true);
1497
 
1498
        $user1 = self::getDataGenerator()->create_user();
1499
        $user2 = self::getDataGenerator()->create_user();
1500
 
1501
        $this->setUser($user1);
1502
        $preferences = array(
1503
            array(
1504
                'name' => 'calendar_maxevents',
1505
                'value' => 4,
1506
                'userid' => $user2->id
1507
            )
1508
        );
1509
 
1510
        $result = core_user_external::set_user_preferences($preferences);
1511
 
1512
        $this->assertCount(1, $result['warnings']);
1513
        $this->assertCount(0, $result['saved']);
1514
        $this->assertEquals('nopermission', $result['warnings'][0]['warningcode']);
1515
        $this->assertEquals($user2->id, $result['warnings'][0]['itemid']);
1516
    }
1517
 
1518
    /**
1519
     * Test update_user_preferences unsetting an existing preference.
1520
     */
11 efrain 1521
    public function test_update_user_preferences_unset(): void {
1 efrain 1522
        global $DB;
1523
        $this->resetAfterTest(true);
1524
 
1525
        $user = self::getDataGenerator()->create_user();
1526
 
1527
        // Save users preferences.
1528
        $this->setAdminUser();
1529
        $preferences = array(
1530
            array(
1531
                'name' => 'htmleditor',
1441 ariadna 1532
                'value' => 'textarea',
1 efrain 1533
                'userid' => $user->id,
1534
            )
1535
        );
1536
 
1537
        $result = core_user_external::set_user_preferences($preferences);
1538
        $result = external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result);
1539
        $this->assertCount(0, $result['warnings']);
1540
        $this->assertCount(1, $result['saved']);
1541
 
1542
        // Get preference from DB to avoid cache.
1441 ariadna 1543
        $this->assertEquals('textarea', $DB->get_field('user_preferences', 'value',
1 efrain 1544
            array('userid' => $user->id, 'name' => 'htmleditor')));
1545
 
1546
        // Now, unset.
1547
        $result = core_user_external::update_user_preferences($user->id, null, array(array('type' => 'htmleditor')));
1548
 
1549
        $this->assertEquals(0, $DB->count_records('user_preferences', array('userid' => $user->id, 'name' => 'htmleditor')));
1550
    }
1551
 
1552
    /**
1553
     * Test agree_site_policy
1554
     */
11 efrain 1555
    public function test_agree_site_policy(): void {
1 efrain 1556
        global $CFG, $DB, $USER;
1557
        $this->resetAfterTest(true);
1558
 
1559
        $user = self::getDataGenerator()->create_user();
1560
        $this->setUser($user);
1561
 
1562
        // Site policy not set.
1563
        $result = core_user_external::agree_site_policy();
1564
        $result = external_api::clean_returnvalue(core_user_external::agree_site_policy_returns(), $result);
1565
        $this->assertFalse($result['status']);
1566
        $this->assertCount(1, $result['warnings']);
1567
        $this->assertEquals('nositepolicy', $result['warnings'][0]['warningcode']);
1568
 
1569
        // Set a policy issue.
1570
        $CFG->sitepolicy = 'https://moodle.org';
1571
        $this->assertEquals(0, $USER->policyagreed);
1572
 
1573
        $result = core_user_external::agree_site_policy();
1574
        $result = external_api::clean_returnvalue(core_user_external::agree_site_policy_returns(), $result);
1575
        $this->assertTrue($result['status']);
1576
        $this->assertCount(0, $result['warnings']);
1577
        $this->assertEquals(1, $USER->policyagreed);
1578
        $this->assertEquals(1, $DB->get_field('user', 'policyagreed', array('id' => $USER->id)));
1579
 
1580
        // Try again, we should get a warning.
1581
        $result = core_user_external::agree_site_policy();
1582
        $result = external_api::clean_returnvalue(core_user_external::agree_site_policy_returns(), $result);
1583
        $this->assertFalse($result['status']);
1584
        $this->assertCount(1, $result['warnings']);
1585
        $this->assertEquals('alreadyagreed', $result['warnings'][0]['warningcode']);
1586
 
1587
        // Set something to make require_login throws an exception.
1588
        $otheruser = self::getDataGenerator()->create_user();
1589
        $this->setUser($otheruser);
1590
 
1591
        $DB->set_field('user', 'lastname', '', array('id' => $USER->id));
1592
        $USER->lastname = '';
1593
        try {
1594
            $result = core_user_external::agree_site_policy();
1595
            $this->fail('Expecting \'usernotfullysetup\' moodle_exception to be thrown');
1596
        } catch (\moodle_exception $e) {
1597
            $this->assertEquals('usernotfullysetup', $e->errorcode);
1598
        } catch (\Exception $e) {
1599
            $this->fail('Expecting \'usernotfullysetup\' moodle_exception to be thrown.');
1600
        }
1601
    }
1602
 
1603
    /**
1604
     * Test get_private_files_info
1605
     */
11 efrain 1606
    public function test_get_private_files_info(): void {
1 efrain 1607
 
1608
        $this->resetAfterTest(true);
1609
        $user = self::getDataGenerator()->create_user();
1610
        $this->setUser($user);
1611
        $usercontext = \context_user::instance($user->id);
1612
 
1613
        $filerecord = array(
1614
            'contextid' => $usercontext->id,
1615
            'component' => 'user',
1616
            'filearea'  => 'private',
1617
            'itemid'    => 0,
1618
            'filepath'  => '/',
1619
            'filename'  => 'thefile',
1620
        );
1621
 
1622
        $fs = get_file_storage();
1623
        $file = $fs->create_file_from_string($filerecord, 'abc');
1624
 
1625
        // Get my private files information.
1626
        $result = core_user_external::get_private_files_info();
1627
        $result = external_api::clean_returnvalue(core_user_external::get_private_files_info_returns(), $result);
1628
        $this->assertEquals(1, $result['filecount']);
1629
        $this->assertEquals($file->get_filesize(), $result['filesize']);
1630
        $this->assertEquals(0, $result['foldercount']);
1631
        $this->assertEquals($file->get_filesize(), $result['filesizewithoutreferences']);
1632
 
1633
        // As admin, get user information.
1634
        $this->setAdminUser();
1635
        $result = core_user_external::get_private_files_info($user->id);
1636
        $result = external_api::clean_returnvalue(core_user_external::get_private_files_info_returns(), $result);
1637
        $this->assertEquals(1, $result['filecount']);
1638
        $this->assertEquals($file->get_filesize(), $result['filesize']);
1639
        $this->assertEquals(0, $result['foldercount']);
1640
        $this->assertEquals($file->get_filesize(), $result['filesizewithoutreferences']);
1641
    }
1642
 
1643
    /**
1644
     * Test get_private_files_info missing permissions.
1645
     */
11 efrain 1646
    public function test_get_private_files_info_missing_permissions(): void {
1 efrain 1647
 
1648
        $this->resetAfterTest(true);
1649
        $user1 = self::getDataGenerator()->create_user();
1650
        $user2 = self::getDataGenerator()->create_user();
1651
        $this->setUser($user1);
1652
 
1653
        $this->expectException('required_capability_exception');
1654
        // Try to retrieve other user private files info.
1655
        core_user_external::get_private_files_info($user2->id);
1656
    }
1657
 
1658
    /**
1659
     * Test the functionality of the {@see \core_user\external\search_identity} class.
1660
     */
11 efrain 1661
    public function test_external_search_identity(): void {
1 efrain 1662
        global $CFG;
1663
 
1664
        $this->resetAfterTest(true);
1665
        $this->setAdminUser();
1666
 
1667
        $user1 = self::getDataGenerator()->create_user([
1668
            'firstname' => 'Firstone',
1669
            'lastname' => 'Lastone',
1670
            'username' => 'usernameone',
1671
            'idnumber' => 'idnumberone',
1672
            'email' => 'userone@example.com',
1673
            'phone1' => 'tel1',
1674
            'phone2' => 'tel2',
1675
            'department' => 'Department Foo',
1676
            'institution' => 'Institution Foo',
1677
            'city' => 'City One',
1678
            'country' => 'AU',
1679
        ]);
1680
 
1681
        $user2 = self::getDataGenerator()->create_user([
1682
            'firstname' => 'Firsttwo',
1683
            'lastname' => 'Lasttwo',
1684
            'username' => 'usernametwo',
1685
            'idnumber' => 'idnumbertwo',
1686
            'email' => 'usertwo@example.com',
1687
            'phone1' => 'tel1',
1688
            'phone2' => 'tel2',
1689
            'department' => 'Department Foo',
1690
            'institution' => 'Institution Foo',
1691
            'city' => 'City One',
1692
            'country' => 'AU',
1693
        ]);
1694
 
1695
        $user3 = self::getDataGenerator()->create_user([
1696
            'firstname' => 'Firstthree',
1697
            'lastname' => 'Lastthree',
1698
            'username' => 'usernamethree',
1699
            'idnumber' => 'idnumberthree',
1700
            'email' => 'userthree@example.com',
1701
            'phone1' => 'tel1',
1702
            'phone2' => 'tel2',
1703
            'department' => 'Department Foo',
1704
            'institution' => 'Institution Foo',
1705
            'city' => 'City One',
1706
            'country' => 'AU',
1707
        ]);
1708
 
1709
        $CFG->showuseridentity = 'email,idnumber,city';
1710
        $CFG->maxusersperpage = 3;
1711
 
1712
        $result = \core_user\external\search_identity::execute('Lastt');
1713
        $result = external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result);
1714
 
1715
        $this->assertEquals(2, count($result['list']));
1716
        $this->assertEquals(3, $result['maxusersperpage']);
1717
        $this->assertEquals(false, $result['overflow']);
1718
 
1719
        foreach ($result['list'] as $user) {
1720
            $this->assertEquals(3, count($user['extrafields']));
1721
            $this->assertEquals('email', $user['extrafields'][0]['name']);
1722
            $this->assertEquals('idnumber', $user['extrafields'][1]['name']);
1723
            $this->assertEquals('city', $user['extrafields'][2]['name']);
1724
        }
1725
 
1726
        $CFG->showuseridentity = 'username';
1727
        $CFG->maxusersperpage = 2;
1728
 
1729
        $result = \core_user\external\search_identity::execute('Firstt');
1730
        $result = external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result);
1731
 
1732
        $this->assertEquals(2, count($result['list']));
1733
        $this->assertEquals(2, $result['maxusersperpage']);
1734
        $this->assertEquals(false, $result['overflow']);
1735
 
1736
        foreach ($result['list'] as $user) {
1737
            $this->assertEquals(1, count($user['extrafields']));
1738
            $this->assertEquals('username', $user['extrafields'][0]['name']);
1739
        }
1740
 
1741
        $CFG->showuseridentity = 'email';
1742
        $CFG->maxusersperpage = 2;
1743
 
1744
        $result = \core_user\external\search_identity::execute('City One');
1745
        $result = external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result);
1746
 
1747
        $this->assertEquals(0, count($result['list']));
1748
        $this->assertEquals(2, $result['maxusersperpage']);
1749
        $this->assertEquals(false, $result['overflow']);
1750
 
1751
        $CFG->showuseridentity = 'city';
1752
        $CFG->maxusersperpage = 2;
1753
 
1754
        foreach ($result['list'] as $user) {
1755
            $this->assertEquals(1, count($user['extrafields']));
1756
            $this->assertEquals('username', $user['extrafields'][0]['name']);
1757
        }
1758
 
1759
        $result = \core_user\external\search_identity::execute('City One');
1760
        $result = external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result);
1761
 
1762
        $this->assertEquals(2, count($result['list']));
1763
        $this->assertEquals(2, $result['maxusersperpage']);
1764
        $this->assertEquals(true, $result['overflow']);
1765
    }
1766
 
1767
    /**
1768
     * Test functionality of the {@see \core_user\external\search_identity} class with alternativefullnameformat defined.
1769
     */
11 efrain 1770
    public function test_external_search_identity_with_alternativefullnameformat(): void {
1 efrain 1771
        global $CFG;
1772
 
1773
        $this->resetAfterTest(true);
1774
        $this->setAdminUser();
1775
 
1776
        $user1 = self::getDataGenerator()->create_user([
1777
            'lastname' => '小柳',
1778
            'lastnamephonetic' => 'Koyanagi',
1779
            'firstname' => '秋',
1780
            'firstnamephonetic' => 'Aki',
1781
            'email' => 'koyanagiaki@example.com',
1782
            'country' => 'JP',
1783
        ]);
1784
 
1785
        $CFG->showuseridentity = 'email';
1786
        $CFG->maxusersperpage = 3;
1787
        $CFG->alternativefullnameformat =
1788
            '<ruby>lastname firstname <rp>(</rp><rt>lastnamephonetic firstnamephonetic</rt><rp>)</rp></ruby>';
1789
 
1790
        $result = \core_user\external\search_identity::execute('Ak');
1791
        $result = external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result);
1792
 
1793
        $this->assertEquals(1, count($result['list']));
1794
        $this->assertEquals(3, $result['maxusersperpage']);
1795
        $this->assertEquals(false, $result['overflow']);
1796
 
1797
        foreach ($result['list'] as $user) {
1798
            $this->assertEquals(1, count($user['extrafields']));
1799
            $this->assertEquals('email', $user['extrafields'][0]['name']);
1800
        }
1801
    }
1802
 
1803
    /**
1804
     * Test verifying that update_user_preferences prevents changes to the default homepage for other users.
1805
     */
11 efrain 1806
    public function test_update_user_preferences_homepage_permission_callback(): void {
1 efrain 1807
        global $DB;
1808
        $this->resetAfterTest();
1809
 
1810
        $user = self::getDataGenerator()->create_user();
1811
        $this->setUser($user);
1812
        $adminuser = get_admin();
1813
 
1814
        // Allow user selection of the default homepage via preferences.
1815
        set_config('defaulthomepage', HOMEPAGE_USER);
1816
 
1817
        // Try to save another user's home page preference which uses the permissioncallback.
1818
        $preferences = [
1819
            [
1820
                'name' => 'user_home_page_preference',
1821
                'value' => '3',
1822
                'userid' => $adminuser->id,
1823
            ]
1824
        ];
1825
        $result = core_user_external::set_user_preferences($preferences);
1826
        $result = external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result);
1827
        $this->assertCount(1, $result['warnings']);
1828
        $this->assertCount(0, $result['saved']);
1829
 
1830
        // Verify no change to the preference, checking from DB to avoid cache.
1831
        $this->assertEquals(null, $DB->get_field('user_preferences', 'value',
1832
            ['userid' => $adminuser->id, 'name' => 'user_home_page_preference']));
1833
    }
1834
}