externallib.php 51.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

17

18
19
20
/**
 * External user API
 *
21
22
23
 * @package    core_user
 * @category   external
 * @copyright  2009 Petr Skodak
24
25
26
27
28
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

require_once("$CFG->libdir/externallib.php");

29
/**
30
31
32
33
34
35
36
 * User external functions
 *
 * @package    core_user
 * @category   external
 * @copyright  2011 Jerome Mouneyrac
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @since Moodle 2.2
37
38
 */
class core_user_external extends external_api {
39

Petr Skoda's avatar
Petr Skoda committed
40
41
    /**
     * Returns description of method parameters
42
     *
Petr Skoda's avatar
Petr Skoda committed
43
     * @return external_function_parameters
44
     * @since Moodle 2.2
Petr Skoda's avatar
Petr Skoda committed
45
     */
skodak's avatar
skodak committed
46
    public static function create_users_parameters() {
Petr Skoda's avatar
Petr Skoda committed
47
48
        global $CFG;

49
50
51
52
53
        return new external_function_parameters(
            array(
                'users' => new external_multiple_structure(
                    new external_single_structure(
                        array(
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
                            'username'            => new external_value(PARAM_USERNAME, 'Username policy is defined in Moodle security config.'),
                            'password'            => new external_value(PARAM_RAW, 'Plain text password consisting of any characters'),
                            'firstname'           => new external_value(PARAM_NOTAGS, 'The first name(s) of the user'),
                            'lastname'            => new external_value(PARAM_NOTAGS, 'The family name of the user'),
                            'email'               => new external_value(PARAM_EMAIL, 'A valid and unique email address'),
                            'auth'                => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_DEFAULT, 'manual', NULL_NOT_ALLOWED),
                            'idnumber'            => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_DEFAULT, ''),
                            'lang'                => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_DEFAULT, $CFG->lang, NULL_NOT_ALLOWED),
                            'theme'               => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
                            'timezone'            => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
                            'mailformat'          => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
                            'description'         => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL),
                            'city'                => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
                            'country'             => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
                            'firstnamephonetic'   => new external_value(PARAM_NOTAGS, 'The first name(s) phonetically of the user', VALUE_OPTIONAL),
                            'lastnamephonetic'    => new external_value(PARAM_NOTAGS, 'The family name phonetically of the user', VALUE_OPTIONAL),
                            'middlename'          => new external_value(PARAM_NOTAGS, 'The middle name of the user', VALUE_OPTIONAL),
                            'alternatename'       => new external_value(PARAM_NOTAGS, 'The alternate name of the user', VALUE_OPTIONAL),
                            'preferences'         => new external_multiple_structure(
73
74
                                new external_single_structure(
                                    array(
Petr Skoda's avatar
Petr Skoda committed
75
                                        'type'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preference'),
76
77
                                        'value' => new external_value(PARAM_RAW, 'The value of the preference')
                                    )
78
                                ), 'User preferences', VALUE_OPTIONAL),
79
80
81
                            'customfields' => new external_multiple_structure(
                                new external_single_structure(
                                    array(
Petr Skoda's avatar
Petr Skoda committed
82
                                        'type'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the custom field'),
83
84
                                        'value' => new external_value(PARAM_RAW, 'The value of the custom field')
                                    )
85
                                ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL)
86
87
88
89
90
                        )
                    )
                )
            )
        );
91
92
    }

skodak's avatar
skodak committed
93
    /**
94
95
     * Create one or more users
     *
96
     * @param array $users An array of users to create.
Petr Skoda's avatar
Petr Skoda committed
97
     * @return array An array of arrays
98
     * @since Moodle 2.2
99
     */
Petr Skoda's avatar
Petr Skoda committed
100
    public static function create_users($users) {
101
        global $CFG, $DB;
102
        require_once($CFG->dirroot."/lib/weblib.php");
103
        require_once($CFG->dirroot."/user/lib.php");
104
        require_once($CFG->dirroot."/user/profile/lib.php"); //required for customfields related function
105

106
        // Ensure the current user is allowed to run this function
107
        $context = context_system::instance();
108
        self::validate_context($context);
109
        require_capability('moodle/user:create', $context);
110

111
112
        // Do basic automatic PARAM checks on incoming data, using params description
        // If any problems are found then exceptions are thrown with helpful error messages
Petr Skoda's avatar
Petr Skoda committed
113
        $params = self::validate_parameters(self::create_users_parameters(), array('users'=>$users));
114

Petr Skoda's avatar
Petr Skoda committed
115
116
117
118
119
        $availableauths  = get_plugin_list('auth');
        unset($availableauths['mnet']);       // these would need mnethostid too
        unset($availableauths['webservice']); // we do not want new webservice users for now

        $availablethemes = get_plugin_list('theme');
120
        $availablelangs  = get_string_manager()->get_list_of_translations();
121

122
        $transaction = $DB->start_delegated_transaction();
123

124
        $userids = array();
Petr Skoda's avatar
Petr Skoda committed
125
        foreach ($params['users'] as $user) {
Petr Skoda's avatar
Petr Skoda committed
126
127
128
            // Make sure that the username doesn't already exist
            if ($DB->record_exists('user', array('username'=>$user['username'], 'mnethostid'=>$CFG->mnet_localhost_id))) {
                throw new invalid_parameter_exception('Username already exists: '.$user['username']);
129
130
            }

Petr Skoda's avatar
Petr Skoda committed
131
132
133
            // Make sure auth is valid
            if (empty($availableauths[$user['auth']])) {
                throw new invalid_parameter_exception('Invalid authentication type: '.$user['auth']);
134
135
            }

Petr Skoda's avatar
Petr Skoda committed
136
137
138
            // Make sure lang is valid
            if (empty($availablelangs[$user['lang']])) {
                throw new invalid_parameter_exception('Invalid language code: '.$user['lang']);
139
140
            }

Petr Skoda's avatar
Petr Skoda committed
141
            // Make sure lang is valid
142
143
144
145
            if (!empty($user['theme']) && empty($availablethemes[$user['theme']])) { //theme is VALUE_OPTIONAL,
                                                                                     // so no default value.
                                                                                     // We need to test if the client sent it
                                                                                     // => !empty($user['theme'])
Petr Skoda's avatar
Petr Skoda committed
146
                throw new invalid_parameter_exception('Invalid theme: '.$user['theme']);
147
            }
148

149
            $user['confirmed'] = true;
150
            $user['mnethostid'] = $CFG->mnet_localhost_id;
151

152
153
154
155
156
157
158
159
160
            // Start of user info validation.
            // Lets make sure we validate current user info as handled by current GUI. see user/editadvanced_form.php function validation()
            if (!validate_email($user['email'])) {
                throw new invalid_parameter_exception('Email address is invalid: '.$user['email']);
            } else if ($DB->record_exists('user', array('email'=>$user['email'], 'mnethostid'=>$user['mnethostid']))) {
                throw new invalid_parameter_exception('Email address already exists: '.$user['email']);
            }
            // End of user info validation.

161
162
            // create the user data now!
            $user['id'] = user_create_user($user);
163

164
165
166
167
168
169
170
171
172
            // custom fields
            if(!empty($user['customfields'])) {
                foreach($user['customfields'] as $customfield) {
                    $user["profile_field_".$customfield['type']] = $customfield['value']; //profile_save_data() saves profile file
                                                                                            //it's expecting a user with the correct id,
                                                                                            //and custom field to be named profile_field_"shortname"
                }
                profile_save_data((object) $user);
            }
Petr Skoda's avatar
Petr Skoda committed
173

174
175
176
177
178
179
            //preferences
            if (!empty($user['preferences'])) {
                foreach($user['preferences'] as $preference) {
                    set_user_preference($preference['type'], $preference['value'],$user['id']);
                }
            }
skodak's avatar
skodak committed
180

181
            $userids[] = array('id'=>$user['id'], 'username'=>$user['username']);
182
183
        }

184
        $transaction->allow_commit();
Petr Skoda's avatar
Petr Skoda committed
185

186
        return $userids;
187
188
    }

Petr Skoda's avatar
Petr Skoda committed
189
190
   /**
     * Returns description of method result value
191
     *
Petr Skoda's avatar
Petr Skoda committed
192
     * @return external_description
193
     * @since Moodle 2.2
Petr Skoda's avatar
Petr Skoda committed
194
195
196
197
198
199
     */
    public static function create_users_returns() {
        return new external_multiple_structure(
            new external_single_structure(
                array(
                    'id'       => new external_value(PARAM_INT, 'user id'),
200
                    'username' => new external_value(PARAM_USERNAME, 'user name'),
Petr Skoda's avatar
Petr Skoda committed
201
202
203
                )
            )
        );
skodak's avatar
skodak committed
204
205
206
    }


Petr Skoda's avatar
Petr Skoda committed
207
208
    /**
     * Returns description of method parameters
209
     *
Petr Skoda's avatar
Petr Skoda committed
210
     * @return external_function_parameters
211
     * @since Moodle 2.2
Petr Skoda's avatar
Petr Skoda committed
212
     */
skodak's avatar
skodak committed
213
    public static function delete_users_parameters() {
Petr Skoda's avatar
Petr Skoda committed
214
215
216
217
218
        return new external_function_parameters(
            array(
                'userids' => new external_multiple_structure(new external_value(PARAM_INT, 'user ID')),
            )
        );
skodak's avatar
skodak committed
219
    }
Petr Skoda's avatar
Petr Skoda committed
220

221
222
    /**
     * Delete users
223
     *
224
     * @param array $userids
Sam Hemelryk's avatar
Sam Hemelryk committed
225
     * @return null
226
     * @since Moodle 2.2
227
     */
228
    public static function delete_users($userids) {
229
        global $CFG, $DB, $USER;
230
        require_once($CFG->dirroot."/user/lib.php");
231
232

        // Ensure the current user is allowed to run this function
233
        $context = context_system::instance();
234
235
236
        require_capability('moodle/user:delete', $context);
        self::validate_context($context);

237
        $params = self::validate_parameters(self::delete_users_parameters(), array('userids'=>$userids));
238
239
240
241
242

        $transaction = $DB->start_delegated_transaction();

        foreach ($params['userids'] as $userid) {
            $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0), '*', MUST_EXIST);
243
            // must not allow deleting of admins or self!!!
244
245
246
247
248
            if (is_siteadmin($user)) {
                throw new moodle_exception('useradminodelete', 'error');
            }
            if ($USER->id == $user->id) {
                throw new moodle_exception('usernotdeletederror', 'error');
249
            }
250
            user_delete_user($user);
251
252
253
254
255
        }

        $transaction->allow_commit();

        return null;
256
    }
Petr Skoda's avatar
Petr Skoda committed
257
258
259

   /**
     * Returns description of method result value
260
261
262
     *
     * @return null
     * @since Moodle 2.2
Petr Skoda's avatar
Petr Skoda committed
263
     */
skodak's avatar
skodak committed
264
    public static function delete_users_returns() {
Petr Skoda's avatar
Petr Skoda committed
265
        return null;
skodak's avatar
skodak committed
266
    }
267
268


Petr Skoda's avatar
Petr Skoda committed
269
270
    /**
     * Returns description of method parameters
271
     *
Petr Skoda's avatar
Petr Skoda committed
272
     * @return external_function_parameters
273
     * @since Moodle 2.2
Petr Skoda's avatar
Petr Skoda committed
274
     */
skodak's avatar
skodak committed
275
    public static function update_users_parameters() {
276
        global $CFG;
277
        return new external_function_parameters(
278
279
280
281
            array(
                'users' => new external_multiple_structure(
                    new external_single_structure(
                        array(
282
                            'id'    => new external_value(PARAM_INT, 'ID of the user'),
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
                            'username'            => new external_value(PARAM_USERNAME, 'Username policy is defined in Moodle security config.', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
                            'password'            => new external_value(PARAM_RAW, 'Plain text password consisting of any characters', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
                            'firstname'           => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
                            'lastname'            => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
                            'email'               => new external_value(PARAM_EMAIL, 'A valid and unique email address', VALUE_OPTIONAL, '',NULL_NOT_ALLOWED),
                            'auth'                => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
                            'idnumber'            => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
                            'lang'                => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
                            'theme'               => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
                            'timezone'            => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
                            'mailformat'          => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
                            'description'         => new external_value(PARAM_TEXT, 'User profile description, no HTML', VALUE_OPTIONAL),
                            'city'                => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
                            'country'             => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
                            'firstnamephonetic'   => new external_value(PARAM_NOTAGS, 'The first name(s) phonetically of the user', VALUE_OPTIONAL),
                            'lastnamephonetic'    => new external_value(PARAM_NOTAGS, 'The family name phonetically of the user', VALUE_OPTIONAL),
                            'middlename'          => new external_value(PARAM_NOTAGS, 'The middle name of the user', VALUE_OPTIONAL),
                            'alternatename'       => new external_value(PARAM_NOTAGS, 'The alternate name of the user', VALUE_OPTIONAL),
                            'customfields'        => new external_multiple_structure(
302
303
304
305
306
                                new external_single_structure(
                                    array(
                                        'type'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the custom field'),
                                        'value' => new external_value(PARAM_RAW, 'The value of the custom field')
                                    )
307
                                ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
308
309
310
311
312
313
314
                            'preferences' => new external_multiple_structure(
                                new external_single_structure(
                                    array(
                                        'type'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preference'),
                                        'value' => new external_value(PARAM_RAW, 'The value of the preference')
                                    )
                                ), 'User preferences', VALUE_OPTIONAL),
315
316
317
318
319
                        )
                    )
                )
            )
        );
skodak's avatar
skodak committed
320
    }
321

322
323
    /**
     * Update users
324
     *
325
     * @param array $users
Sam Hemelryk's avatar
Sam Hemelryk committed
326
     * @return null
327
     * @since Moodle 2.2
328
     */
329
330
    public static function update_users($users) {
        global $CFG, $DB;
331
        require_once($CFG->dirroot."/user/lib.php");
332
        require_once($CFG->dirroot."/user/profile/lib.php"); //required for customfields related function
333
334

        // Ensure the current user is allowed to run this function
335
        $context = context_system::instance();
336
337
338
339
340
341
342
343
        require_capability('moodle/user:update', $context);
        self::validate_context($context);

        $params = self::validate_parameters(self::update_users_parameters(), array('users'=>$users));

        $transaction = $DB->start_delegated_transaction();

        foreach ($params['users'] as $user) {
344
            user_update_user($user);
345
346
347
348
349
350
351
352
353
354
            //update user custom fields
            if(!empty($user['customfields'])) {

                foreach($user['customfields'] as $customfield) {
                    $user["profile_field_".$customfield['type']] = $customfield['value']; //profile_save_data() saves profile file
                                                                                            //it's expecting a user with the correct id,
                                                                                            //and custom field to be named profile_field_"shortname"
                }
                profile_save_data((object) $user);
            }
355
356
357
358
359
360
361

            //preferences
            if (!empty($user['preferences'])) {
                foreach($user['preferences'] as $preference) {
                    set_user_preference($preference['type'], $preference['value'],$user['id']);
                }
            }
362
363
364
365
366
        }

        $transaction->allow_commit();

        return null;
367
    }
Petr Skoda's avatar
Petr Skoda committed
368
369
370

   /**
     * Returns description of method result value
371
372
373
     *
     * @return null
     * @since Moodle 2.2
Petr Skoda's avatar
Petr Skoda committed
374
     */
skodak's avatar
skodak committed
375
    public static function update_users_returns() {
Petr Skoda's avatar
Petr Skoda committed
376
        return null;
skodak's avatar
skodak committed
377
378
    }

379
380
381
382
   /**
   * Returns description of method parameters
   *
   * @return external_function_parameters
383
   * @since Moodle 2.4
384
   */
385
    public static function get_users_by_field_parameters() {
386
387
        return new external_function_parameters(
            array(
388
389
390
391
                'field' => new external_value(PARAM_ALPHA, 'the search field can be
                    \'id\' or \'idnumber\' or \'username\' or \'email\''),
                'values' => new external_multiple_structure(
                        new external_value(PARAM_RAW, 'the value to match'))
392
393
394
395
396
            )
        );
    }

    /**
397
     * Get user information for a unique field.
398
     *
399
400
401
402
     * @param string $field
     * @param array $values
     * @return array An array of arrays containg user profiles.
     * @since Moodle 2.4
403
     */
404
    public static function get_users_by_field($field, $values) {
405
406
407
        global $CFG, $USER, $DB;
        require_once($CFG->dirroot . "/user/lib.php");

408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
        $params = self::validate_parameters(self::get_users_by_field_parameters(),
                array('field' => $field, 'values' => $values));

        // This array will keep all the users that are allowed to be searched,
        // according to the current user's privileges.
        $cleanedvalues = array();

        switch ($field) {
            case 'id':
                $paramtype = PARAM_INT;
                break;
            case 'idnumber':
                $paramtype = PARAM_RAW;
                break;
            case 'username':
423
                $paramtype = PARAM_RAW;
424
425
426
427
428
429
430
                break;
            case 'email':
                $paramtype = PARAM_EMAIL;
                break;
            default:
                throw new coding_exception('invalid field parameter',
                        'The search field \'' . $field . '\' is not supported, look at the web service documentation');
431
432
        }

433
434
435
436
437
438
439
440
        // Clean the values
        foreach ($values as $value) {
            $cleanedvalue = clean_param($value, $paramtype);
            if ( $value != $cleanedvalue) {
                throw new invalid_parameter_exception('The field \'' . $field .
                        '\' value is invalid: ' . $value . '(cleaned value: '.$cleanedvalue.')');
            }
            $cleanedvalues[] = $cleanedvalue;
441
442
        }

443
444
        // Retrieve the users
        $users = $DB->get_records_list('user', $field, $cleanedvalues, 'id');
445

446
447
        // Finally retrieve each users information
        $returnedusers = array();
448
449
450
        foreach ($users as $user) {
            $userdetails = user_get_user_details_courses($user);

451
452
453
454
            // Return the user only if the searched field is returned
            // Otherwise it means that the $USER was not allowed to search the returned user
            if (!empty($userdetails) and !empty($userdetails[$field])) {
                $returnedusers[] = $userdetails;
455
456
457
            }
        }

458
        return $returnedusers;
459
460
461
462
463
    }

    /**
     * Returns description of method result value
     *
464
465
     * @return external_multiple_structure
     * @since Moodle 2.4
466
     */
467
    public static function get_users_by_field_returns() {
468
        return new external_multiple_structure(self::user_description());
469
470
471
472
    }


    /**
473
     * Returns description of get_users() parameters.
474
475
     *
     * @return external_function_parameters
476
     * @since Moodle 2.5
477
478
479
480
481
482
483
     */
    public static function get_users_parameters() {
        return new external_function_parameters(
            array(
                'criteria' => new external_multiple_structure(
                    new external_single_structure(
                        array(
484
485
486
487
488
489
490
491
492
                            'key' => new external_value(PARAM_ALPHA, 'the user column to search, expected keys (value format) are:
                                "id" (int) matching user id,
                                "lastname" (string) user last name (Note: you can use % for searching but it may be considerably slower!),
                                "firstname" (string) user first name (Note: you can use % for searching but it may be considerably slower!),
                                "idnumber" (string) matching user idnumber,
                                "username" (string) matching user username,
                                "email" (string) user email (Note: you can use % for searching but it may be considerably slower!),
                                "auth" (string) matching user auth plugin'),
                            'value' => new external_value(PARAM_RAW, 'the value to search')
493
494
                        )
                    ), 'the key/value pairs to be considered in user search. Values can not be empty.
495
                        Specify different keys only once (fullname => \'user1\', auth => \'manual\', ...) -
496
                        key occurences are forbidden.
497
                        The search is executed with AND operator on the criterias. Invalid criterias (keys) are ignored,
498
499
500
                        the search is still executed on the valid criterias.
                        You can search without criteria, but the function is not designed for it.
                        It could very slow or timeout. The function is designed to search some specific users.'
501
502
503
504
505
                )
            )
        );
    }

506
    /**
507
     * Retrieve matching user.
508
     *
509
510
511
     * @param array $criteria the allowed array keys are id/lastname/firstname/idnumber/username/email/auth.
     * @return array An array of arrays containing user profiles.
     * @since Moodle 2.5
512
513
514
515
516
517
518
519
520
     */
    public static function get_users($criteria = array()) {
        global $CFG, $USER, $DB;

        require_once($CFG->dirroot . "/user/lib.php");

        $params = self::validate_parameters(self::get_users_parameters(),
                array('criteria' => $criteria));

521
        // Validate the criteria and retrieve the users.
522
523
524
        $users = array();
        $warnings = array();
        $sqlparams = array();
525
526
527
528
        $usedkeys = array();

        // Do not retrieve deleted users.
        $sql = ' deleted = 0';
529

530
        foreach ($params['criteria'] as $criteriaindex => $criteria) {
531
532
533
534
535
536
537
538

            // Check that the criteria has never been used.
            if (array_key_exists($criteria['key'], $usedkeys)) {
                throw new moodle_exception('keyalreadyset', '', '', null, 'The key ' . $criteria['key'] . ' can only be sent once');
            } else {
                $usedkeys[$criteria['key']] = true;
            }

539
            $invalidcriteria = false;
540
            // Clean the parameters.
541
542
543
544
545
546
547
548
549
            $paramtype = PARAM_RAW;
            switch ($criteria['key']) {
                case 'id':
                    $paramtype = PARAM_INT;
                    break;
                case 'idnumber':
                    $paramtype = PARAM_RAW;
                    break;
                case 'username':
550
                    $paramtype = PARAM_RAW;
551
552
                    break;
                case 'email':
553
                    // We use PARAM_RAW to allow searches with %.
554
555
556
557
558
559
560
561
562
563
                    $paramtype = PARAM_RAW;
                    break;
                case 'auth':
                    $paramtype = PARAM_AUTH;
                    break;
                case 'lastname':
                case 'firstname':
                    $paramtype = PARAM_TEXT;
                    break;
                default:
564
565
                    // Send back a warning that this search key is not supported in this version.
                    // This warning will make the function extandable without breaking clients.
566
                    $warnings[] = array(
567
                        'item' => $criteria['key'],
568
                        'warningcode' => 'invalidfieldparameter',
569
                        'message' => 'The search key \'' . $criteria['key'] . '\' is not supported, look at the web service documentation'
570
                    );
571
572
573
574
                    // Do not add this invalid criteria to the created SQL request.
                    $invalidcriteria = true;
                    unset($params['criteria'][$criteriaindex]);
                    break;
575
576
            }

577
578
            if (!$invalidcriteria) {
                $cleanedvalue = clean_param($criteria['value'], $paramtype);
579

580
                $sql .= ' AND ';
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599

                // Create the SQL.
                switch ($criteria['key']) {
                    case 'id':
                    case 'idnumber':
                    case 'username':
                    case 'auth':
                        $sql .= $criteria['key'] . ' = :' . $criteria['key'];
                        $sqlparams[$criteria['key']] = $cleanedvalue;
                        break;
                    case 'email':
                    case 'lastname':
                    case 'firstname':
                        $sql .= $DB->sql_like($criteria['key'], ':' . $criteria['key'], false);
                        $sqlparams[$criteria['key']] = $cleanedvalue;
                        break;
                    default:
                        break;
                }
600
601
602
603
604
            }
        }

        $users = $DB->get_records_select('user', $sql, $sqlparams, 'id ASC');

605
        // Finally retrieve each users information.
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
        $returnedusers = array();
        foreach ($users as $user) {
            $userdetails = user_get_user_details_courses($user);

            // Return the user only if all the searched fields are returned.
            // Otherwise it means that the $USER was not allowed to search the returned user.
            if (!empty($userdetails)) {
                $validuser = true;

                foreach($params['criteria'] as $criteria) {
                    if (empty($userdetails[$criteria['key']])) {
                        $validuser = false;
                    }
                }

                if ($validuser) {
                    $returnedusers[] = $userdetails;
                }
            }
        }

        return array('users' => $returnedusers, 'warnings' => $warnings);
    }

    /**
631
     * Returns description of get_users result value.
632
633
     *
     * @return external_description
634
     * @since Moodle 2.5
635
636
637
638
     */
    public static function get_users_returns() {
        return new external_single_structure(
            array('users' => new external_multiple_structure(
639
                                self::user_description()
640
                             ),
641
                  'warnings' => new external_warnings('always set to \'key\'', 'faulty key name')
642
643
644
645
            )
        );
    }

Petr Skoda's avatar
Petr Skoda committed
646
647
    /**
     * Returns description of method parameters
648
     *
Petr Skoda's avatar
Petr Skoda committed
649
     * @return external_function_parameters
650
     * @since Moodle 2.2
651
652
     * @deprecated Moodle 2.5 MDL-38030 - Please do not call this function any more.
     * @see core_user_external::get_users_by_field_parameters()
Petr Skoda's avatar
Petr Skoda committed
653
     */
654
    public static function get_users_by_id_parameters() {
Petr Skoda's avatar
Petr Skoda committed
655
        return new external_function_parameters(
656
657
658
                array(
                    'userids' => new external_multiple_structure(new external_value(PARAM_INT, 'user ID')),
                )
Petr Skoda's avatar
Petr Skoda committed
659
        );
skodak's avatar
skodak committed
660
    }
Petr Skoda's avatar
Petr Skoda committed
661

Petr Skoda's avatar
Petr Skoda committed
662
663
    /**
     * Get user information
664
665
666
     * - This function is matching the permissions of /user/profil.php
     * - It is also matching some permissions from /user/editadvanced.php for the following fields:
     *   auth, confirmed, idnumber, lang, theme, timezone, mailformat
667
     *
Petr Skoda's avatar
Petr Skoda committed
668
669
     * @param array $userids  array of user ids
     * @return array An array of arrays describing users
670
     * @since Moodle 2.2
671
672
     * @deprecated Moodle 2.5 MDL-38030 - Please do not call this function any more.
     * @see core_user_external::get_users_by_field()
Petr Skoda's avatar
Petr Skoda committed
673
     */
674
    public static function get_users_by_id($userids) {
675
        global $CFG, $USER, $DB;
676
        require_once($CFG->dirroot . "/user/lib.php");
677

678
679
        $params = self::validate_parameters(self::get_users_by_id_parameters(),
                array('userids'=>$userids));
680

Dongsheng Cai's avatar
Dongsheng Cai committed
681
682
683
684
685
686
        list($uselect, $ujoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx');
        list($sqluserids, $params) = $DB->get_in_or_equal($userids);
        $usersql = "SELECT u.* $uselect
                      FROM {user} u $ujoin
                     WHERE u.id $sqluserids";
        $users = $DB->get_recordset_sql($usersql, $params);
skodak's avatar
skodak committed
687

688
        $result = array();
689
        $hasuserupdatecap = has_capability('moodle/user:update', context_system::instance());
skodak's avatar
skodak committed
690
        foreach ($users as $user) {
Dongsheng Cai's avatar
Dongsheng Cai committed
691
692
693
694
            if (!empty($user->deleted)) {
                continue;
            }
            context_instance_preload($user);
695
            $usercontext = context_user::instance($user->id, IGNORE_MISSING);
696
            self::validate_context($usercontext);
697
698
            $currentuser = ($user->id == $USER->id);

699
700
701
702
703
704
705
706
707
708
            if ($userarray  = user_get_user_details($user)) {
                //fields matching permissions from /user/editadvanced.php
                if ($currentuser or $hasuserupdatecap) {
                    $userarray['auth']       = $user->auth;
                    $userarray['confirmed']  = $user->confirmed;
                    $userarray['idnumber']   = $user->idnumber;
                    $userarray['lang']       = $user->lang;
                    $userarray['theme']      = $user->theme;
                    $userarray['timezone']   = $user->timezone;
                    $userarray['mailformat'] = $user->mailformat;
709
                }
710
                $result[] = $userarray;
Dongsheng Cai's avatar
Dongsheng Cai committed
711
            }
712
        }
Dongsheng Cai's avatar
Dongsheng Cai committed
713
        $users->close();
Petr Skoda's avatar
Petr Skoda committed
714
715

        return $result;
skodak's avatar
skodak committed
716
    }
Petr Skoda's avatar
Petr Skoda committed
717

718
    /**
Petr Skoda's avatar
Petr Skoda committed
719
     * Returns description of method result value
720
     *
Petr Skoda's avatar
Petr Skoda committed
721
     * @return external_description
722
     * @since Moodle 2.2
723
724
     * @deprecated Moodle 2.5 MDL-38030 - Please do not call this function any more.
     * @see core_user_external::get_users_by_field_returns()
Petr Skoda's avatar
Petr Skoda committed
725
     */
726
    public static function get_users_by_id_returns() {
727
728
        $additionalfields = array (
            'enrolledcourses' => new external_multiple_structure(
Damyon Wiese's avatar
Damyon Wiese committed
729
730
731
732
733
734
735
            new external_single_structure(
                array(
                    'id'  => new external_value(PARAM_INT, 'Id of the course'),
                    'fullname'  => new external_value(PARAM_RAW, 'Fullname of the course'),
                    'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
                )
            ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL));
736
        return new external_multiple_structure(self::user_description($additionalfields));
Dongsheng Cai's avatar
Dongsheng Cai committed
737
    }
738

Dongsheng Cai's avatar
Dongsheng Cai committed
739
740
    /**
     * Returns description of method parameters
741
     *
Dongsheng Cai's avatar
Dongsheng Cai committed
742
     * @return external_function_parameters
743
     * @since Moodle 2.2
Dongsheng Cai's avatar
Dongsheng Cai committed
744
     */
745
    public static function get_course_user_profiles_parameters() {
Dongsheng Cai's avatar
Dongsheng Cai committed
746
747
748
749
750
751
752
        return new external_function_parameters(
            array(
                'userlist' => new external_multiple_structure(
                    new external_single_structure(
                        array(
                            'userid'    => new external_value(PARAM_INT, 'userid'),
                            'courseid'    => new external_value(PARAM_INT, 'courseid'),
753
                        )
Dongsheng Cai's avatar
Dongsheng Cai committed
754
                    )
Petr Skoda's avatar
Petr Skoda committed
755
                )
Dongsheng Cai's avatar
Dongsheng Cai committed
756
757
758
759
760
761
            )
        );
    }

    /**
     * Get course participant's details
762
     *
Dongsheng Cai's avatar
Dongsheng Cai committed
763
764
     * @param array $userlist  array of user ids and according course ids
     * @return array An array of arrays describing course participants
765
     * @since Moodle 2.2
Dongsheng Cai's avatar
Dongsheng Cai committed
766
     */
767
    public static function get_course_user_profiles($userlist) {
Dongsheng Cai's avatar
Dongsheng Cai committed
768
769
        global $CFG, $USER, $DB;
        require_once($CFG->dirroot . "/user/lib.php");
770
        $params = self::validate_parameters(self::get_course_user_profiles_parameters(), array('userlist'=>$userlist));
Dongsheng Cai's avatar
Dongsheng Cai committed
771
772
773
774
775
776
777
778
779
780
781
782

        $userids = array();
        $courseids = array();
        foreach ($params['userlist'] as $value) {
            $userids[] = $value['userid'];
            $courseids[$value['userid']] = $value['courseid'];
        }

        // cache all courses
        $courses = array();
        list($cselect, $cjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
        list($sqlcourseids, $params) = $DB->get_in_or_equal(array_unique($courseids));
783
        $coursesql = "SELECT c.* $cselect
Dongsheng Cai's avatar
Dongsheng Cai committed
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
                        FROM {course} c $cjoin
                       WHERE c.id $sqlcourseids";
        $rs = $DB->get_recordset_sql($coursesql, $params);
        foreach ($rs as $course) {
            // adding course contexts to cache
            context_instance_preload($course);
            // cache courses
            $courses[$course->id] = $course;
        }
        $rs->close();

        list($uselect, $ujoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx');
        list($sqluserids, $params) = $DB->get_in_or_equal($userids);
        $usersql = "SELECT u.* $uselect
                      FROM {user} u $ujoin
                     WHERE u.id $sqluserids";
        $users = $DB->get_recordset_sql($usersql, $params);
        $result = array();
        foreach ($users as $user) {
            if (!empty($user->deleted)) {
                continue;
            }
            context_instance_preload($user);
            $course = $courses[$courseids[$user->id]];
808
            $context = context_course::instance($courseids[$user->id], IGNORE_MISSING);
Dongsheng Cai's avatar
Dongsheng Cai committed
809
            self::validate_context($context);
810
811
            if ($userarray = user_get_user_details($user, $course)) {
                $result[] = $userarray;
Dongsheng Cai's avatar
Dongsheng Cai committed
812
            }
813
        }
Dongsheng Cai's avatar
Dongsheng Cai committed
814

815
        $users->close();
Dongsheng Cai's avatar
Dongsheng Cai committed
816

817
818
        return $result;
    }
Dongsheng Cai's avatar
Dongsheng Cai committed
819

820
821
    /**
     * Returns description of method result value
822
     *
823
     * @return external_description
824
     * @since Moodle 2.2
825
     */
826
    public static function get_course_user_profiles_returns() {
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
        $additionalfields = array(
                    'groups' => new external_multiple_structure(
                        new external_single_structure(
                            array(
                                'id'  => new external_value(PARAM_INT, 'group id'),
                                'name' => new external_value(PARAM_RAW, 'group name'),
                                'description' => new external_value(PARAM_RAW, 'group description'),
                                'descriptionformat' => new external_format_value('description'),
                            )
                        ), 'user groups', VALUE_OPTIONAL),
                    'roles' => new external_multiple_structure(
                        new external_single_structure(
                            array(
                                'roleid'       => new external_value(PARAM_INT, 'role id'),
                                'name'         => new external_value(PARAM_RAW, 'role name'),
                                'shortname'    => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
                                'sortorder'    => new external_value(PARAM_INT, 'role sortorder')
                            )
                        ), 'user roles', VALUE_OPTIONAL),
                    'enrolledcourses' => new external_multiple_structure(
Damyon Wiese's avatar
Damyon Wiese committed
847
848
849
850
851
852
853
                        new external_single_structure(
                            array(
                                'id'  => new external_value(PARAM_INT, 'Id of the course'),
                                'fullname'  => new external_value(PARAM_RAW, 'Fullname of the course'),
                                'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
                            )
                        ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
854
855
                    );

856
        return new external_multiple_structure(self::user_description($additionalfields));
857
858
859
860
861
    }

    /**
     * Create user return value description.
     *
862
     * @param array $additionalfields some additional field
863
864
     * @return single_structure_description
     */
865
    public static function user_description($additionalfields = array()) {
866
        $userfields = array(
867
                    'id'    => new external_value(PARAM_INT, 'ID of the user'),
868
                    'username'    => new external_value(PARAM_RAW, 'The username', VALUE_OPTIONAL),
869
870
871
872
                    'firstname'   => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
                    'lastname'    => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
                    'fullname'    => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
                    'email'       => new external_value(PARAM_TEXT, 'An email address - allow email as root@localhost', VALUE_OPTIONAL),
873
                    'address'     => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL),
874
875
876
877
878
879
880
881
882
                    'phone1'      => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
                    'phone2'      => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
                    'icq'         => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL),
                    'skype'       => new external_value(PARAM_NOTAGS, 'skype id', VALUE_OPTIONAL),
                    'yahoo'       => new external_value(PARAM_NOTAGS, 'yahoo id', VALUE_OPTIONAL),
                    'aim'         => new external_value(PARAM_NOTAGS, 'aim id', VALUE_OPTIONAL),
                    'msn'         => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
                    'department'  => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
                    'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
883
                    'idnumber'    => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
884
885
886
                    'interests'   => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
                    'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
                    'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
887
888
889
890
891
892
                    'auth'        => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_OPTIONAL),
                    'confirmed'   => new external_value(PARAM_INT, 'Active user: 1 if confirmed, 0 otherwise', VALUE_OPTIONAL),
                    'lang'        => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_OPTIONAL),
                    'theme'       => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
                    'timezone'    => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
                    'mailformat'  => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
893
                    'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
894
                    'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
895
896
897
898
899
900
901
902
903
904
905
906
907
                    'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
                    'url'         => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
                    'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
                    'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version'),
                    'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version'),
                    'customfields' => new external_multiple_structure(
                        new external_single_structure(
                            array(
                                'type'  => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
                                'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
                                'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
                                'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
                            )
908
                        ), 'User custom fields (also known as user profile fields)', VALUE_OPTIONAL),
909
910
911
912
913
914
                    'preferences' => new external_multiple_structure(
                        new external_single_structure(
                            array(
                                'name'  => new external_value(PARAM_ALPHANUMEXT, 'The name of the preferences'),
                                'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
                            )
915
916
917
918
919
920
                    ), 'Users preferences', VALUE_OPTIONAL)
                );
        if (!empty($additionalfields)) {
            $userfields = array_merge($userfields, $additionalfields);
        }
        return new external_single_structure($userfields);
921
    }
922

923
924
}

925
926
927
928
929
930
931
932
933
 /**
 * Deprecated user external functions
 *
 * @package    core_user
 * @copyright  2009 Petr Skodak
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @since Moodle 2.0
 * @deprecated Moodle 2.2 MDL-29106 - Please do not use this class any more.
 * @see core_user_external
934
935
936
937
938
 */
class moodle_user_external extends external_api {

    /**
     * Returns description of method parameters
939
     *
940
     * @return external_function_parameters
941
942
943
     * @since Moodle 2.0
     * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
     * @see core_user_external::create_users_parameters()
944
945
946
947
948
949
950
     */
    public static function create_users_parameters() {
        return core_user_external::create_users_parameters();
    }

    /**
     * Create one or more users
951
     *
952
953
     * @param array $users  An array of users to create.
     * @return array An array of arrays
954
955
956
     * @since Moodle 2.0
     * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
     * @see core_user_external::create_users()
957
958
959
960
961
962
963
     */
    public static function create_users($users) {
        return core_user_external::create_users($users);
    }

   /**
     * Returns description of method result value
964
     *
965
     * @return external_description
966
967
968
     * @since Moodle 2.0
     * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
     * @see core_user_external::create_users_returns()
969
970
971
972
973
974
975
976
     */
    public static function create_users_returns() {
        return core_user_external::create_users_returns();
    }


    /**
     * Returns description of method parameters
977
     *
978
     * @return external_function_parameters
979
980
981
     * @since Moodle 2.0
     * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
     * @see core_user_external::delete_users_parameters()
982
983
984
985
986
987
988
     */
    public static function delete_users_parameters() {
        return core_user_external::delete_users_parameters();
    }

    /**
     * Delete users
989
     *
990
     * @param array $userids
Sam Hemelryk's avatar
Sam Hemelryk committed
991
     * @return null
992
993
994
     * @since Moodle 2.0
     * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
     * @see core_user_external::delete_users()
995
996
997
998
999
1000
     */
    public static function delete_users($userids) {
        return core_user_external::delete_users($userids);
    }

   /**
For faster browsing, not all history is shown. View entire blame