MDL-59876 core_user: Add required library for function.
[moodle.git] / user / externallib.php
CommitLineData
ef22c1b6 1<?php
ef22c1b6 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 * External user API
19 *
4615817d
JM
20 * @package core_user
21 * @category external
22 * @copyright 2009 Petr Skodak
ef22c1b6 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
e71687ba
JL
26defined('MOODLE_INTERNAL') || die();
27
ef22c1b6 28require_once("$CFG->libdir/externallib.php");
29
5d1017e1 30/**
4615817d
JM
31 * User external functions
32 *
33 * @package core_user
34 * @category external
35 * @copyright 2011 Jerome Mouneyrac
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 * @since Moodle 2.2
5d1017e1
JM
38 */
39class core_user_external extends external_api {
ef22c1b6 40
7b472b32
PS
41 /**
42 * Returns description of method parameters
4615817d 43 *
7b472b32 44 * @return external_function_parameters
4615817d 45 * @since Moodle 2.2
7b472b32 46 */
d4e13355 47 public static function create_users_parameters() {
667b496a
PS
48 global $CFG;
49
35b9a80a 50 return new external_function_parameters(
51 array(
52 'users' => new external_multiple_structure(
53 new external_single_structure(
54 array(
a2ed6e69 55 'username' =>
ac9768fc 56 new external_value(core_user::get_property_type('username'), 'Username policy is defined in Moodle security config.'),
a2ed6e69 57 'password' =>
ac9768fc 58 new external_value(core_user::get_property_type('password'), 'Plain text password consisting of any characters', VALUE_OPTIONAL),
e71a336c
DNA
59 'createpassword' =>
60 new external_value(PARAM_BOOL, 'True if password should be created and mailed to user.',
61 VALUE_OPTIONAL),
a2ed6e69 62 'firstname' =>
ac9768fc 63 new external_value(core_user::get_property_type('firstname'), 'The first name(s) of the user'),
a2ed6e69 64 'lastname' =>
ac9768fc 65 new external_value(core_user::get_property_type('lastname'), 'The family name of the user'),
a2ed6e69 66 'email' =>
ac9768fc 67 new external_value(core_user::get_property_type('email'), 'A valid and unique email address'),
a2ed6e69 68 'auth' =>
abc25c01 69 new external_value(core_user::get_property_type('auth'), 'Auth plugins include manual, ldap, etc', VALUE_DEFAULT,
ac9768fc 70 'manual', core_user::get_property_null('auth')),
a2ed6e69 71 'idnumber' =>
ac9768fc 72 new external_value(core_user::get_property_type('idnumber'), 'An arbitrary ID code number perhaps from the institution',
a2ed6e69
SH
73 VALUE_DEFAULT, ''),
74 'lang' =>
ac9768fc
SL
75 new external_value(core_user::get_property_type('lang'), 'Language code such as "en", must exist on server', VALUE_DEFAULT,
76 core_user::get_property_default('lang'), core_user::get_property_null('lang')),
a2ed6e69 77 'calendartype' =>
ac9768fc 78 new external_value(core_user::get_property_type('calendartype'), 'Calendar type such as "gregorian", must exist on server',
a2ed6e69
SH
79 VALUE_DEFAULT, $CFG->calendartype, VALUE_OPTIONAL),
80 'theme' =>
ac9768fc 81 new external_value(core_user::get_property_type('theme'), 'Theme name such as "standard", must exist on server',
a2ed6e69
SH
82 VALUE_OPTIONAL),
83 'timezone' =>
ac9768fc 84 new external_value(core_user::get_property_type('timezone'), 'Timezone code such as Australia/Perth, or 99 for default',
a2ed6e69
SH
85 VALUE_OPTIONAL),
86 'mailformat' =>
ac9768fc 87 new external_value(core_user::get_property_type('mailformat'), 'Mail format code is 0 for plain text, 1 for HTML etc',
a2ed6e69
SH
88 VALUE_OPTIONAL),
89 'description' =>
ac9768fc 90 new external_value(core_user::get_property_type('description'), 'User profile description, no HTML', VALUE_OPTIONAL),
a2ed6e69 91 'city' =>
ac9768fc 92 new external_value(core_user::get_property_type('city'), 'Home city of the user', VALUE_OPTIONAL),
a2ed6e69 93 'country' =>
ac9768fc 94 new external_value(core_user::get_property_type('country'), 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
a2ed6e69 95 'firstnamephonetic' =>
ac9768fc 96 new external_value(core_user::get_property_type('firstnamephonetic'), 'The first name(s) phonetically of the user', VALUE_OPTIONAL),
a2ed6e69 97 'lastnamephonetic' =>
ac9768fc 98 new external_value(core_user::get_property_type('lastnamephonetic'), 'The family name phonetically of the user', VALUE_OPTIONAL),
a2ed6e69 99 'middlename' =>
ac9768fc 100 new external_value(core_user::get_property_type('middlename'), 'The middle name of the user', VALUE_OPTIONAL),
a2ed6e69 101 'alternatename' =>
ac9768fc 102 new external_value(core_user::get_property_type('alternatename'), 'The alternate name of the user', VALUE_OPTIONAL),
a2ed6e69 103 'preferences' => new external_multiple_structure(
35b9a80a 104 new external_single_structure(
105 array(
7b472b32 106 'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the preference'),
35b9a80a 107 'value' => new external_value(PARAM_RAW, 'The value of the preference')
108 )
fb79269b 109 ), 'User preferences', VALUE_OPTIONAL),
35b9a80a 110 'customfields' => new external_multiple_structure(
111 new external_single_structure(
112 array(
7b472b32 113 'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the custom field'),
35b9a80a 114 'value' => new external_value(PARAM_RAW, 'The value of the custom field')
115 )
6bb31e40 116 ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL)
35b9a80a 117 )
118 )
119 )
120 )
121 );
625f0a24 122 }
123
d4e13355 124 /**
a2ed6e69 125 * Create one or more users.
5de592b1 126 *
a2ed6e69 127 * @throws invalid_parameter_exception
4615817d 128 * @param array $users An array of users to create.
71864f15 129 * @return array An array of arrays
4615817d 130 * @since Moodle 2.2
5de592b1 131 */
7b472b32 132 public static function create_users($users) {
ef22c1b6 133 global $CFG, $DB;
25eb9090 134 require_once($CFG->dirroot."/lib/weblib.php");
fb79269b 135 require_once($CFG->dirroot."/user/lib.php");
2c97abef 136 require_once($CFG->dirroot."/user/editlib.php");
a2ed6e69 137 require_once($CFG->dirroot."/user/profile/lib.php"); // Required for customfields related function.
109b453b 138
a2ed6e69 139 // Ensure the current user is allowed to run this function.
43731030 140 $context = context_system::instance();
ef22c1b6 141 self::validate_context($context);
fb79269b 142 require_capability('moodle/user:create', $context);
d9ad0103 143
a2ed6e69
SH
144 // Do basic automatic PARAM checks on incoming data, using params description.
145 // If any problems are found then exceptions are thrown with helpful error messages.
146 $params = self::validate_parameters(self::create_users_parameters(), array('users' => $users));
109b453b 147
bd3b3bba 148 $availableauths = core_component::get_plugin_list('auth');
a2ed6e69
SH
149 unset($availableauths['mnet']); // These would need mnethostid too.
150 unset($availableauths['webservice']); // We do not want new webservice users for now.
667b496a 151
bd3b3bba 152 $availablethemes = core_component::get_plugin_list('theme');
1f96e907 153 $availablelangs = get_string_manager()->get_list_of_translations();
5de592b1 154
38b76f3c 155 $transaction = $DB->start_delegated_transaction();
5de592b1 156
fb79269b 157 $userids = array();
e71a336c 158 $createpassword = false;
7b472b32 159 foreach ($params['users'] as $user) {
a2ed6e69
SH
160 // Make sure that the username doesn't already exist.
161 if ($DB->record_exists('user', array('username' => $user['username'], 'mnethostid' => $CFG->mnet_localhost_id))) {
667b496a 162 throw new invalid_parameter_exception('Username already exists: '.$user['username']);
ef22c1b6 163 }
ef22c1b6 164
a2ed6e69 165 // Make sure auth is valid.
667b496a
PS
166 if (empty($availableauths[$user['auth']])) {
167 throw new invalid_parameter_exception('Invalid authentication type: '.$user['auth']);
ef22c1b6 168 }
169
a2ed6e69 170 // Make sure lang is valid.
667b496a
PS
171 if (empty($availablelangs[$user['lang']])) {
172 throw new invalid_parameter_exception('Invalid language code: '.$user['lang']);
ef22c1b6 173 }
174
a2ed6e69
SH
175 // Make sure lang is valid.
176 if (!empty($user['theme']) && empty($availablethemes[$user['theme']])) { // Theme is VALUE_OPTIONAL,
177 // so no default value
fb79269b 178 // We need to test if the client sent it
a2ed6e69 179 // => !empty($user['theme']).
667b496a 180 throw new invalid_parameter_exception('Invalid theme: '.$user['theme']);
ef22c1b6 181 }
5de592b1 182
e71a336c
DNA
183 // Make sure we have a password or have to create one.
184 if (empty($user['password']) && empty($user['createpassword'])) {
dcfae879 185 throw new invalid_parameter_exception('Invalid password: you must provide a password, or set createpassword.');
e71a336c
DNA
186 }
187
fb79269b 188 $user['confirmed'] = true;
a1988186 189 $user['mnethostid'] = $CFG->mnet_localhost_id;
30a4fb1b 190
25eb9090 191 // Start of user info validation.
a2ed6e69 192 // Make sure we validate current user info as handled by current GUI. See user/editadvanced_form.php func validation().
25eb9090
AB
193 if (!validate_email($user['email'])) {
194 throw new invalid_parameter_exception('Email address is invalid: '.$user['email']);
9ccc3729
DM
195 } else if (empty($CFG->allowaccountssameemail) &&
196 $DB->record_exists('user', array('email' => $user['email'], 'mnethostid' => $user['mnethostid']))) {
25eb9090
AB
197 throw new invalid_parameter_exception('Email address already exists: '.$user['email']);
198 }
199 // End of user info validation.
200
e71a336c
DNA
201 $createpassword = !empty($user['createpassword']);
202 unset($user['createpassword']);
203 if ($createpassword) {
204 $user['password'] = '';
205 $updatepassword = false;
206 } else {
207 $updatepassword = true;
208 }
209
a2ed6e69 210 // Create the user data now!
e71a336c 211 $user['id'] = user_create_user($user, $updatepassword, false);
25eb9090 212
a2ed6e69
SH
213 // Custom fields.
214 if (!empty($user['customfields'])) {
215 foreach ($user['customfields'] as $customfield) {
216 // Profile_save_data() saves profile file it's expecting a user with the correct id,
217 // and custom field to be named profile_field_"shortname".
218 $user["profile_field_".$customfield['type']] = $customfield['value'];
30a4fb1b 219 }
220 profile_save_data((object) $user);
221 }
667b496a 222
e71a336c
DNA
223 if ($createpassword) {
224 $userobject = (object)$user;
225 setnew_password_and_mail($userobject);
226 unset_user_preference('create_password', $userobject);
227 set_user_preference('auth_forcepasswordchange', 1, $userobject);
228 }
229
2b55cb1b
RT
230 // Trigger event.
231 \core\event\user_created::create_from_userid($user['id'])->trigger();
232
a2ed6e69 233 // Preferences.
d9ad0103 234 if (!empty($user['preferences'])) {
6e65554e 235 $userpref = (object)$user;
a2ed6e69 236 foreach ($user['preferences'] as $preference) {
6e65554e 237 $userpref->{'preference_'.$preference['type']} = $preference['value'];
d9ad0103 238 }
6e65554e 239 useredit_update_user_preference($userpref);
d9ad0103 240 }
d4e13355 241
a2ed6e69 242 $userids[] = array('id' => $user['id'], 'username' => $user['username']);
ef22c1b6 243 }
244
38b76f3c 245 $transaction->allow_commit();
667b496a 246
fb79269b 247 return $userids;
ef22c1b6 248 }
249
a2ed6e69 250 /**
7b472b32 251 * Returns description of method result value
4615817d 252 *
7b472b32 253 * @return external_description
4615817d 254 * @since Moodle 2.2
7b472b32
PS
255 */
256 public static function create_users_returns() {
257 return new external_multiple_structure(
258 new external_single_structure(
259 array(
ac9768fc
SL
260 'id' => new external_value(core_user::get_property_type('id'), 'user id'),
261 'username' => new external_value(core_user::get_property_type('username'), 'user name'),
7b472b32
PS
262 )
263 )
264 );
d4e13355 265 }
266
267
930680cb
PS
268 /**
269 * Returns description of method parameters
4615817d 270 *
930680cb 271 * @return external_function_parameters
4615817d 272 * @since Moodle 2.2
930680cb 273 */
d4e13355 274 public static function delete_users_parameters() {
930680cb
PS
275 return new external_function_parameters(
276 array(
ac9768fc 277 'userids' => new external_multiple_structure(new external_value(core_user::get_property_type('id'), 'user ID')),
930680cb
PS
278 )
279 );
d4e13355 280 }
930680cb 281
5d1017e1
JM
282 /**
283 * Delete users
4615817d 284 *
a2ed6e69 285 * @throws moodle_exception
5d1017e1 286 * @param array $userids
e6acc551 287 * @return null
4615817d 288 * @since Moodle 2.2
5d1017e1 289 */
38b76f3c 290 public static function delete_users($userids) {
b73a28be 291 global $CFG, $DB, $USER;
fb79269b 292 require_once($CFG->dirroot."/user/lib.php");
38b76f3c 293
a2ed6e69 294 // Ensure the current user is allowed to run this function.
43731030 295 $context = context_system::instance();
38b76f3c
PS
296 require_capability('moodle/user:delete', $context);
297 self::validate_context($context);
298
a2ed6e69 299 $params = self::validate_parameters(self::delete_users_parameters(), array('userids' => $userids));
38b76f3c
PS
300
301 $transaction = $DB->start_delegated_transaction();
38b76f3c
PS
302
303 foreach ($params['userids'] as $userid) {
a2ed6e69
SH
304 $user = $DB->get_record('user', array('id' => $userid, 'deleted' => 0), '*', MUST_EXIST);
305 // Must not allow deleting of admins or self!!!
4f622c38
PS
306 if (is_siteadmin($user)) {
307 throw new moodle_exception('useradminodelete', 'error');
308 }
309 if ($USER->id == $user->id) {
310 throw new moodle_exception('usernotdeletederror', 'error');
b73a28be 311 }
fb79269b 312 user_delete_user($user);
38b76f3c
PS
313 }
314
315 $transaction->allow_commit();
316
317 return null;
ef22c1b6 318 }
930680cb 319
a2ed6e69 320 /**
930680cb 321 * Returns description of method result value
4615817d
JM
322 *
323 * @return null
324 * @since Moodle 2.2
930680cb 325 */
d4e13355 326 public static function delete_users_returns() {
930680cb 327 return null;
d4e13355 328 }
ef22c1b6 329
a0eabdd3 330 /**
c598f278 331 * Returns description of method parameters.
a0eabdd3
RW
332 *
333 * @return external_function_parameters
334 * @since Moodle 3.2
335 */
c598f278 336 public static function update_user_preferences_parameters() {
a0eabdd3
RW
337 return new external_function_parameters(
338 array(
c598f278
MN
339 'userid' => new external_value(PARAM_INT, 'id of the user, default to current user', VALUE_DEFAULT, 0),
340 'emailstop' => new external_value(core_user::get_property_type('emailstop'),
341 'Enable or disable notifications for this user', VALUE_DEFAULT, null),
342 'preferences' => new external_multiple_structure(
343 new external_single_structure(
344 array(
345 'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the preference'),
346 'value' => new external_value(PARAM_RAW, 'The value of the preference')
347 )
348 ), 'User preferences', VALUE_DEFAULT, array()
a0eabdd3
RW
349 )
350 )
351 );
352 }
353
354 /**
c598f278 355 * Update the user's preferences.
a0eabdd3 356 *
c598f278
MN
357 * @param int $userid
358 * @param bool|null $emailstop
359 * @param array $preferences
a0eabdd3
RW
360 * @return null
361 * @since Moodle 3.2
362 */
c598f278
MN
363 public static function update_user_preferences($userid, $emailstop = null, $preferences = array()) {
364 global $USER, $CFG;
a0eabdd3 365
c598f278 366 require_once($CFG->dirroot . '/user/lib.php');
6e65554e
MG
367 require_once($CFG->dirroot . '/user/editlib.php');
368 require_once($CFG->dirroot . '/message/lib.php');
a0eabdd3 369
c598f278
MN
370 if (empty($userid)) {
371 $userid = $USER->id;
372 }
a0eabdd3 373
c598f278
MN
374 $systemcontext = context_system::instance();
375 self::validate_context($systemcontext);
376 $params = array(
377 'userid' => $userid,
378 'emailstop' => $emailstop,
379 'preferences' => $preferences
380 );
381 self::validate_parameters(self::update_user_preferences_parameters(), $params);
382
a0eabdd3 383 // Preferences.
c598f278 384 if (!empty($preferences)) {
6e65554e 385 $userpref = ['id' => $userid];
c598f278 386 foreach ($preferences as $preference) {
6e65554e 387 $userpref['preference_' . $preference['type']] = $preference['value'];
a0eabdd3 388 }
6e65554e 389 useredit_update_user_preference($userpref);
a0eabdd3
RW
390 }
391
c598f278
MN
392 // Check if they want to update the email.
393 if ($emailstop !== null) {
6e65554e
MG
394 $otheruser = ($userid == $USER->id) ? $USER : core_user::get_user($userid, '*', MUST_EXIST);
395 core_user::require_active_user($otheruser);
396 if (core_message_can_edit_message_profile($otheruser) && $otheruser->emailstop != $emailstop) {
397 $user = new stdClass();
398 $user->id = $userid;
399 $user->emailstop = $emailstop;
400 user_update_user($user);
401
402 // Update the $USER if we should.
403 if ($userid == $USER->id) {
404 $USER->emailstop = $emailstop;
405 }
34eb5fcb
RW
406 }
407 }
408
a0eabdd3
RW
409 return null;
410 }
411
412 /**
413 * Returns description of method result value
414 *
415 * @return null
416 * @since Moodle 3.2
417 */
c598f278 418 public static function update_user_preferences_returns() {
a0eabdd3
RW
419 return null;
420 }
ef22c1b6 421
930680cb
PS
422 /**
423 * Returns description of method parameters
4615817d 424 *
930680cb 425 * @return external_function_parameters
4615817d 426 * @since Moodle 2.2
930680cb 427 */
d4e13355 428 public static function update_users_parameters() {
2336a843 429 return new external_function_parameters(
fb79269b 430 array(
431 'users' => new external_multiple_structure(
432 new external_single_structure(
433 array(
a2ed6e69 434 'id' =>
ac9768fc 435 new external_value(core_user::get_property_type('id'), 'ID of the user'),
a2ed6e69 436 'username' =>
ac9768fc 437 new external_value(core_user::get_property_type('username'), 'Username policy is defined in Moodle security config.',
a2ed6e69
SH
438 VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
439 'password' =>
ac9768fc 440 new external_value(core_user::get_property_type('password'), 'Plain text password consisting of any characters', VALUE_OPTIONAL,
a2ed6e69
SH
441 '', NULL_NOT_ALLOWED),
442 'firstname' =>
ac9768fc 443 new external_value(core_user::get_property_type('firstname'), 'The first name(s) of the user', VALUE_OPTIONAL, '',
a2ed6e69
SH
444 NULL_NOT_ALLOWED),
445 'lastname' =>
ac9768fc 446 new external_value(core_user::get_property_type('lastname'), 'The family name of the user', VALUE_OPTIONAL),
a2ed6e69 447 'email' =>
ac9768fc 448 new external_value(core_user::get_property_type('email'), 'A valid and unique email address', VALUE_OPTIONAL, '',
a2ed6e69
SH
449 NULL_NOT_ALLOWED),
450 'auth' =>
abc25c01 451 new external_value(core_user::get_property_type('auth'), 'Auth plugins include manual, ldap, etc', VALUE_OPTIONAL, '',
a2ed6e69 452 NULL_NOT_ALLOWED),
511db621
AS
453 'suspended' =>
454 new external_value(core_user::get_property_type('suspended'), 'Suspend user account, either false to enable user login or true to disable it', VALUE_OPTIONAL),
a2ed6e69 455 'idnumber' =>
ac9768fc 456 new external_value(core_user::get_property_type('idnumber'), 'An arbitrary ID code number perhaps from the institution',
a2ed6e69
SH
457 VALUE_OPTIONAL),
458 'lang' =>
ac9768fc 459 new external_value(core_user::get_property_type('lang'), 'Language code such as "en", must exist on server',
a2ed6e69
SH
460 VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
461 'calendartype' =>
ac9768fc 462 new external_value(core_user::get_property_type('calendartype'), 'Calendar type such as "gregorian", must exist on server',
a2ed6e69
SH
463 VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
464 'theme' =>
ac9768fc 465 new external_value(core_user::get_property_type('theme'), 'Theme name such as "standard", must exist on server',
a2ed6e69
SH
466 VALUE_OPTIONAL),
467 'timezone' =>
ac9768fc 468 new external_value(core_user::get_property_type('timezone'), 'Timezone code such as Australia/Perth, or 99 for default',
a2ed6e69
SH
469 VALUE_OPTIONAL),
470 'mailformat' =>
ac9768fc 471 new external_value(core_user::get_property_type('mailformat'), 'Mail format code is 0 for plain text, 1 for HTML etc',
a2ed6e69
SH
472 VALUE_OPTIONAL),
473 'description' =>
ac9768fc 474 new external_value(core_user::get_property_type('description'), 'User profile description, no HTML', VALUE_OPTIONAL),
a2ed6e69 475 'city' =>
ac9768fc 476 new external_value(core_user::get_property_type('city'), 'Home city of the user', VALUE_OPTIONAL),
a2ed6e69 477 'country' =>
ac9768fc 478 new external_value(core_user::get_property_type('country'), 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
a2ed6e69 479 'firstnamephonetic' =>
ac9768fc 480 new external_value(core_user::get_property_type('firstnamephonetic'), 'The first name(s) phonetically of the user', VALUE_OPTIONAL),
a2ed6e69 481 'lastnamephonetic' =>
ac9768fc 482 new external_value(core_user::get_property_type('lastnamephonetic'), 'The family name phonetically of the user', VALUE_OPTIONAL),
a2ed6e69 483 'middlename' =>
ac9768fc 484 new external_value(core_user::get_property_type('middlename'), 'The middle name of the user', VALUE_OPTIONAL),
a2ed6e69 485 'alternatename' =>
ac9768fc 486 new external_value(core_user::get_property_type('alternatename'), 'The alternate name of the user', VALUE_OPTIONAL),
5407c5b0
RS
487 'userpicture' =>
488 new external_value(PARAM_INT, 'The itemid where the new user picture '.
489 'has been uploaded to, 0 to delete', VALUE_OPTIONAL),
a2ed6e69 490 'customfields' => new external_multiple_structure(
fb79269b 491 new external_single_structure(
492 array(
493 'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the custom field'),
494 'value' => new external_value(PARAM_RAW, 'The value of the custom field')
495 )
6bb31e40 496 ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
d9ad0103 497 'preferences' => new external_multiple_structure(
498 new external_single_structure(
499 array(
500 'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the preference'),
501 'value' => new external_value(PARAM_RAW, 'The value of the preference')
502 )
503 ), 'User preferences', VALUE_OPTIONAL),
fb79269b 504 )
505 )
506 )
507 )
508 );
d4e13355 509 }
38b76f3c 510
5d1017e1
JM
511 /**
512 * Update users
4615817d 513 *
5d1017e1 514 * @param array $users
e6acc551 515 * @return null
4615817d 516 * @since Moodle 2.2
5d1017e1 517 */
38b76f3c 518 public static function update_users($users) {
42778e12 519 global $CFG, $DB, $USER;
fb79269b 520 require_once($CFG->dirroot."/user/lib.php");
a2ed6e69 521 require_once($CFG->dirroot."/user/profile/lib.php"); // Required for customfields related function.
6e65554e 522 require_once($CFG->dirroot.'/user/editlib.php');
38b76f3c 523
a2ed6e69 524 // Ensure the current user is allowed to run this function.
43731030 525 $context = context_system::instance();
38b76f3c
PS
526 require_capability('moodle/user:update', $context);
527 self::validate_context($context);
528
a2ed6e69 529 $params = self::validate_parameters(self::update_users_parameters(), array('users' => $users));
38b76f3c 530
5407c5b0
RS
531 $filemanageroptions = array('maxbytes' => $CFG->maxbytes,
532 'subdirs' => 0,
533 'maxfiles' => 1,
534 'accepted_types' => 'web_image');
535
38b76f3c
PS
536 $transaction = $DB->start_delegated_transaction();
537
538 foreach ($params['users'] as $user) {
42778e12
JL
539 // First check the user exists.
540 if (!$existinguser = core_user::get_user($user['id'])) {
541 continue;
542 }
543 // Check if we are trying to update an admin.
544 if ($existinguser->id != $USER->id and is_siteadmin($existinguser) and !is_siteadmin($USER)) {
545 continue;
546 }
547 // Other checks (deleted, remote or guest users).
548 if ($existinguser->deleted or is_mnet_remote_user($existinguser) or isguestuser($existinguser->id)) {
549 continue;
550 }
8c4d7cee
JL
551 // Check duplicated emails.
552 if (isset($user['email']) && $user['email'] !== $existinguser->email) {
553 if (!validate_email($user['email'])) {
554 continue;
555 } else if (empty($CFG->allowaccountssameemail) &&
556 $DB->record_exists('user', array('email' => $user['email'], 'mnethostid' => $CFG->mnet_localhost_id))) {
557 continue;
558 }
559 }
560
2b55cb1b 561 user_update_user($user, true, false);
5407c5b0
RS
562
563 // Update user picture if it was specified for this user.
564 if (empty($CFG->disableuserimages) && isset($user['userpicture'])) {
565 $userobject = (object)$user;
566
567 $userobject->deletepicture = null;
568
569 if ($user['userpicture'] == 0) {
570 $userobject->deletepicture = true;
571 } else {
572 $userobject->imagefile = $user['userpicture'];
573 }
574
575 core_user::update_picture($userobject, $filemanageroptions);
576 }
577
a2ed6e69
SH
578 // Update user custom fields.
579 if (!empty($user['customfields'])) {
9baf3a7b 580
a2ed6e69
SH
581 foreach ($user['customfields'] as $customfield) {
582 // Profile_save_data() saves profile file it's expecting a user with the correct id,
583 // and custom field to be named profile_field_"shortname".
584 $user["profile_field_".$customfield['type']] = $customfield['value'];
9baf3a7b 585 }
586 profile_save_data((object) $user);
587 }
d9ad0103 588
2b55cb1b
RT
589 // Trigger event.
590 \core\event\user_updated::create_from_userid($user['id'])->trigger();
591
a2ed6e69 592 // Preferences.
d9ad0103 593 if (!empty($user['preferences'])) {
6e65554e 594 $userpref = clone($existinguser);
a2ed6e69 595 foreach ($user['preferences'] as $preference) {
6e65554e 596 $userpref->{'preference_'.$preference['type']} = $preference['value'];
d9ad0103 597 }
6e65554e 598 useredit_update_user_preference($userpref);
d9ad0103 599 }
511db621
AS
600 if (isset($user['suspended']) and $user['suspended']) {
601 \core\session\manager::kill_user_sessions($user['id']);
602 }
38b76f3c
PS
603 }
604
605 $transaction->allow_commit();
606
607 return null;
ef22c1b6 608 }
930680cb 609
a2ed6e69 610 /**
930680cb 611 * Returns description of method result value
4615817d
JM
612 *
613 * @return null
614 * @since Moodle 2.2
930680cb 615 */
d4e13355 616 public static function update_users_returns() {
930680cb 617 return null;
d4e13355 618 }
619
a2ed6e69
SH
620 /**
621 * Returns description of method parameters
622 *
623 * @return external_function_parameters
624 * @since Moodle 2.4
625 */
c70b9853 626 public static function get_users_by_field_parameters() {
86477112
FS
627 return new external_function_parameters(
628 array(
c70b9853
JM
629 'field' => new external_value(PARAM_ALPHA, 'the search field can be
630 \'id\' or \'idnumber\' or \'username\' or \'email\''),
631 'values' => new external_multiple_structure(
632 new external_value(PARAM_RAW, 'the value to match'))
86477112
FS
633 )
634 );
635 }
636
637 /**
c70b9853 638 * Get user information for a unique field.
86477112 639 *
a2ed6e69
SH
640 * @throws coding_exception
641 * @throws invalid_parameter_exception
c70b9853
JM
642 * @param string $field
643 * @param array $values
644 * @return array An array of arrays containg user profiles.
645 * @since Moodle 2.4
86477112 646 */
c70b9853 647 public static function get_users_by_field($field, $values) {
86477112
FS
648 global $CFG, $USER, $DB;
649 require_once($CFG->dirroot . "/user/lib.php");
650
c70b9853
JM
651 $params = self::validate_parameters(self::get_users_by_field_parameters(),
652 array('field' => $field, 'values' => $values));
653
654 // This array will keep all the users that are allowed to be searched,
655 // according to the current user's privileges.
656 $cleanedvalues = array();
657
658 switch ($field) {
659 case 'id':
ac9768fc 660 $paramtype = core_user::get_property_type('id');
c70b9853
JM
661 break;
662 case 'idnumber':
ac9768fc 663 $paramtype = core_user::get_property_type('idnumber');
c70b9853
JM
664 break;
665 case 'username':
ac9768fc 666 $paramtype = core_user::get_property_type('username');
c70b9853
JM
667 break;
668 case 'email':
ac9768fc 669 $paramtype = core_user::get_property_type('email');
c70b9853
JM
670 break;
671 default:
672 throw new coding_exception('invalid field parameter',
673 'The search field \'' . $field . '\' is not supported, look at the web service documentation');
86477112
FS
674 }
675
a2ed6e69 676 // Clean the values.
c70b9853
JM
677 foreach ($values as $value) {
678 $cleanedvalue = clean_param($value, $paramtype);
679 if ( $value != $cleanedvalue) {
680 throw new invalid_parameter_exception('The field \'' . $field .
681 '\' value is invalid: ' . $value . '(cleaned value: '.$cleanedvalue.')');
682 }
683 $cleanedvalues[] = $cleanedvalue;
86477112
FS
684 }
685
a2ed6e69 686 // Retrieve the users.
c70b9853 687 $users = $DB->get_records_list('user', $field, $cleanedvalues, 'id');
86477112 688
5267d632
DW
689 $context = context_system::instance();
690 self::validate_context($context);
691
a2ed6e69 692 // Finally retrieve each users information.
c70b9853 693 $returnedusers = array();
86477112 694 foreach ($users as $user) {
86477112
FS
695 $userdetails = user_get_user_details_courses($user);
696
a2ed6e69
SH
697 // Return the user only if the searched field is returned.
698 // Otherwise it means that the $USER was not allowed to search the returned user.
c70b9853
JM
699 if (!empty($userdetails) and !empty($userdetails[$field])) {
700 $returnedusers[] = $userdetails;
86477112
FS
701 }
702 }
86477112 703
c70b9853 704 return $returnedusers;
86477112
FS
705 }
706
707 /**
708 * Returns description of method result value
709 *
c70b9853
JM
710 * @return external_multiple_structure
711 * @since Moodle 2.4
86477112 712 */
c70b9853 713 public static function get_users_by_field_returns() {
85e6bf8e 714 return new external_multiple_structure(self::user_description());
b0365ea5
JM
715 }
716
717
718 /**
bb1105ae 719 * Returns description of get_users() parameters.
b0365ea5
JM
720 *
721 * @return external_function_parameters
bb1105ae 722 * @since Moodle 2.5
b0365ea5
JM
723 */
724 public static function get_users_parameters() {
725 return new external_function_parameters(
726 array(
727 'criteria' => new external_multiple_structure(
728 new external_single_structure(
729 array(
bb1105ae
JM
730 'key' => new external_value(PARAM_ALPHA, 'the user column to search, expected keys (value format) are:
731 "id" (int) matching user id,
732 "lastname" (string) user last name (Note: you can use % for searching but it may be considerably slower!),
733 "firstname" (string) user first name (Note: you can use % for searching but it may be considerably slower!),
734 "idnumber" (string) matching user idnumber,
735 "username" (string) matching user username,
736 "email" (string) user email (Note: you can use % for searching but it may be considerably slower!),
737 "auth" (string) matching user auth plugin'),
738 'value' => new external_value(PARAM_RAW, 'the value to search')
b0365ea5
JM
739 )
740 ), 'the key/value pairs to be considered in user search. Values can not be empty.
bb1105ae 741 Specify different keys only once (fullname => \'user1\', auth => \'manual\', ...) -
85e6bf8e 742 key occurences are forbidden.
0c34e803 743 The search is executed with AND operator on the criterias. Invalid criterias (keys) are ignored,
85e6bf8e
JM
744 the search is still executed on the valid criterias.
745 You can search without criteria, but the function is not designed for it.
746 It could very slow or timeout. The function is designed to search some specific users.'
86477112
FS
747 )
748 )
749 );
750 }
751
b0365ea5 752 /**
bb1105ae 753 * Retrieve matching user.
b0365ea5 754 *
a2ed6e69 755 * @throws moodle_exception
bb1105ae
JM
756 * @param array $criteria the allowed array keys are id/lastname/firstname/idnumber/username/email/auth.
757 * @return array An array of arrays containing user profiles.
758 * @since Moodle 2.5
b0365ea5
JM
759 */
760 public static function get_users($criteria = array()) {
761 global $CFG, $USER, $DB;
762
763 require_once($CFG->dirroot . "/user/lib.php");
764
765 $params = self::validate_parameters(self::get_users_parameters(),
766 array('criteria' => $criteria));
767
bb1105ae 768 // Validate the criteria and retrieve the users.
b0365ea5
JM
769 $users = array();
770 $warnings = array();
b0365ea5 771 $sqlparams = array();
85e6bf8e
JM
772 $usedkeys = array();
773
774 // Do not retrieve deleted users.
775 $sql = ' deleted = 0';
b0365ea5 776
0c34e803 777 foreach ($params['criteria'] as $criteriaindex => $criteria) {
85e6bf8e
JM
778
779 // Check that the criteria has never been used.
780 if (array_key_exists($criteria['key'], $usedkeys)) {
781 throw new moodle_exception('keyalreadyset', '', '', null, 'The key ' . $criteria['key'] . ' can only be sent once');
782 } else {
783 $usedkeys[$criteria['key']] = true;
784 }
785
0c34e803 786 $invalidcriteria = false;
bb1105ae 787 // Clean the parameters.
b0365ea5
JM
788 $paramtype = PARAM_RAW;
789 switch ($criteria['key']) {
790 case 'id':
ac9768fc 791 $paramtype = core_user::get_property_type('id');
b0365ea5
JM
792 break;
793 case 'idnumber':
ac9768fc 794 $paramtype = core_user::get_property_type('idnumber');
b0365ea5
JM
795 break;
796 case 'username':
ac9768fc 797 $paramtype = core_user::get_property_type('username');
b0365ea5
JM
798 break;
799 case 'email':
bb1105ae 800 // We use PARAM_RAW to allow searches with %.
ac9768fc 801 $paramtype = core_user::get_property_type('email');
b0365ea5
JM
802 break;
803 case 'auth':
ac9768fc 804 $paramtype = core_user::get_property_type('auth');
b0365ea5
JM
805 break;
806 case 'lastname':
807 case 'firstname':
ac9768fc 808 $paramtype = core_user::get_property_type('firstname');
b0365ea5
JM
809 break;
810 default:
bb1105ae
JM
811 // Send back a warning that this search key is not supported in this version.
812 // This warning will make the function extandable without breaking clients.
b0365ea5 813 $warnings[] = array(
0c34e803 814 'item' => $criteria['key'],
b0365ea5 815 'warningcode' => 'invalidfieldparameter',
a2ed6e69
SH
816 'message' =>
817 'The search key \'' . $criteria['key'] . '\' is not supported, look at the web service documentation'
b0365ea5 818 );
0c34e803
JM
819 // Do not add this invalid criteria to the created SQL request.
820 $invalidcriteria = true;
821 unset($params['criteria'][$criteriaindex]);
822 break;
b0365ea5 823 }
b0365ea5 824
0c34e803
JM
825 if (!$invalidcriteria) {
826 $cleanedvalue = clean_param($criteria['value'], $paramtype);
b0365ea5 827
85e6bf8e 828 $sql .= ' AND ';
0c34e803
JM
829
830 // Create the SQL.
831 switch ($criteria['key']) {
832 case 'id':
833 case 'idnumber':
834 case 'username':
835 case 'auth':
836 $sql .= $criteria['key'] . ' = :' . $criteria['key'];
837 $sqlparams[$criteria['key']] = $cleanedvalue;
838 break;
839 case 'email':
840 case 'lastname':
841 case 'firstname':
842 $sql .= $DB->sql_like($criteria['key'], ':' . $criteria['key'], false);
843 $sqlparams[$criteria['key']] = $cleanedvalue;
844 break;
845 default:
846 break;
847 }
b0365ea5
JM
848 }
849 }
850
851 $users = $DB->get_records_select('user', $sql, $sqlparams, 'id ASC');
852
bb1105ae 853 // Finally retrieve each users information.
b0365ea5
JM
854 $returnedusers = array();
855 foreach ($users as $user) {
b0365ea5
JM
856 $userdetails = user_get_user_details_courses($user);
857
858 // Return the user only if all the searched fields are returned.
859 // Otherwise it means that the $USER was not allowed to search the returned user.
860 if (!empty($userdetails)) {
861 $validuser = true;
862
a2ed6e69 863 foreach ($params['criteria'] as $criteria) {
b0365ea5
JM
864 if (empty($userdetails[$criteria['key']])) {
865 $validuser = false;
866 }
867 }
868
869 if ($validuser) {
870 $returnedusers[] = $userdetails;
871 }
872 }
873 }
874
875 return array('users' => $returnedusers, 'warnings' => $warnings);
876 }
877
878 /**
bb1105ae 879 * Returns description of get_users result value.
b0365ea5
JM
880 *
881 * @return external_description
bb1105ae 882 * @since Moodle 2.5
b0365ea5
JM
883 */
884 public static function get_users_returns() {
885 return new external_single_structure(
886 array('users' => new external_multiple_structure(
85e6bf8e 887 self::user_description()
b0365ea5 888 ),
bb1105ae 889 'warnings' => new external_warnings('always set to \'key\'', 'faulty key name')
b0365ea5
JM
890 )
891 );
892 }
893
7b472b32
PS
894 /**
895 * Returns description of method parameters
4615817d 896 *
7b472b32 897 * @return external_function_parameters
4615817d 898 * @since Moodle 2.2
ea4e96c2 899 */
5d1017e1 900 public static function get_course_user_profiles_parameters() {
ea4e96c2
DC
901 return new external_function_parameters(
902 array(
903 'userlist' => new external_multiple_structure(
904 new external_single_structure(
905 array(
ac9768fc 906 'userid' => new external_value(core_user::get_property_type('id'), 'userid'),
ea4e96c2 907 'courseid' => new external_value(PARAM_INT, 'courseid'),
109b453b 908 )
ea4e96c2 909 )
71864f15 910 )
ea4e96c2
DC
911 )
912 );
913 }
914
915 /**
916 * Get course participant's details
4615817d 917 *
ea4e96c2
DC
918 * @param array $userlist array of user ids and according course ids
919 * @return array An array of arrays describing course participants
4615817d 920 * @since Moodle 2.2
ea4e96c2 921 */
5d1017e1 922 public static function get_course_user_profiles($userlist) {
ea4e96c2
DC
923 global $CFG, $USER, $DB;
924 require_once($CFG->dirroot . "/user/lib.php");
a2ed6e69 925 $params = self::validate_parameters(self::get_course_user_profiles_parameters(), array('userlist' => $userlist));
ea4e96c2
DC
926
927 $userids = array();
928 $courseids = array();
929 foreach ($params['userlist'] as $value) {
930 $userids[] = $value['userid'];
931 $courseids[$value['userid']] = $value['courseid'];
932 }
933
a2ed6e69 934 // Cache all courses.
ea4e96c2 935 $courses = array();
0d352dbc 936 list($sqlcourseids, $params) = $DB->get_in_or_equal(array_unique($courseids), SQL_PARAMS_NAMED);
2e4c0c91
FM
937 $cselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
938 $cjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
939 $params['contextlevel'] = CONTEXT_COURSE;
ecfc06d8 940 $coursesql = "SELECT c.* $cselect
ea4e96c2
DC
941 FROM {course} c $cjoin
942 WHERE c.id $sqlcourseids";
943 $rs = $DB->get_recordset_sql($coursesql, $params);
944 foreach ($rs as $course) {
a2ed6e69 945 // Adding course contexts to cache.
db314f34 946 context_helper::preload_from_record($course);
a2ed6e69 947 // Cache courses.
ea4e96c2
DC
948 $courses[$course->id] = $course;
949 }
950 $rs->close();
951
0d352dbc 952 list($sqluserids, $params) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
2e4c0c91
FM
953 $uselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
954 $ujoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)";
955 $params['contextlevel'] = CONTEXT_USER;
ea4e96c2
DC
956 $usersql = "SELECT u.* $uselect
957 FROM {user} u $ujoin
958 WHERE u.id $sqluserids";
959 $users = $DB->get_recordset_sql($usersql, $params);
960 $result = array();
961 foreach ($users as $user) {
962 if (!empty($user->deleted)) {
963 continue;
964 }
db314f34 965 context_helper::preload_from_record($user);
ea4e96c2 966 $course = $courses[$courseids[$user->id]];
43731030 967 $context = context_course::instance($courseids[$user->id], IGNORE_MISSING);
ea4e96c2 968 self::validate_context($context);
01479290
DC
969 if ($userarray = user_get_user_details($user, $course)) {
970 $result[] = $userarray;
ea4e96c2 971 }
01479290 972 }
ea4e96c2 973
01479290 974 $users->close();
ea4e96c2 975
01479290
DC
976 return $result;
977 }
ea4e96c2 978
01479290
DC
979 /**
980 * Returns description of method result value
4615817d 981 *
01479290 982 * @return external_description
4615817d 983 * @since Moodle 2.2
01479290 984 */
5d1017e1 985 public static function get_course_user_profiles_returns() {
b0365ea5 986 $additionalfields = array(
a2ed6e69
SH
987 'groups' => new external_multiple_structure(
988 new external_single_structure(
989 array(
990 'id' => new external_value(PARAM_INT, 'group id'),
991 'name' => new external_value(PARAM_RAW, 'group name'),
992 'description' => new external_value(PARAM_RAW, 'group description'),
993 'descriptionformat' => new external_format_value('description'),
994 )
995 ), 'user groups', VALUE_OPTIONAL),
996 'roles' => new external_multiple_structure(
997 new external_single_structure(
998 array(
999 'roleid' => new external_value(PARAM_INT, 'role id'),
1000 'name' => new external_value(PARAM_RAW, 'role name'),
1001 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
1002 'sortorder' => new external_value(PARAM_INT, 'role sortorder')
1003 )
1004 ), 'user roles', VALUE_OPTIONAL),
1005 'enrolledcourses' => new external_multiple_structure(
1006 new external_single_structure(
1007 array(
1008 'id' => new external_value(PARAM_INT, 'Id of the course'),
1009 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
1010 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
1011 )
1012 ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
1013 );
b0365ea5 1014
85e6bf8e 1015 return new external_multiple_structure(self::user_description($additionalfields));
b0365ea5
JM
1016 }
1017
1018 /**
1019 * Create user return value description.
1020 *
bb1105ae 1021 * @param array $additionalfields some additional field
b0365ea5
JM
1022 * @return single_structure_description
1023 */
bb1105ae 1024 public static function user_description($additionalfields = array()) {
b0365ea5 1025 $userfields = array(
ac9768fc
SL
1026 'id' => new external_value(core_user::get_property_type('id'), 'ID of the user'),
1027 'username' => new external_value(core_user::get_property_type('username'), 'The username', VALUE_OPTIONAL),
1028 'firstname' => new external_value(core_user::get_property_type('firstname'), 'The first name(s) of the user', VALUE_OPTIONAL),
1029 'lastname' => new external_value(core_user::get_property_type('lastname'), 'The family name of the user', VALUE_OPTIONAL),
1030 'fullname' => new external_value(core_user::get_property_type('firstname'), 'The fullname of the user'),
1031 'email' => new external_value(core_user::get_property_type('email'), 'An email address - allow email as root@localhost', VALUE_OPTIONAL),
1032 'address' => new external_value(core_user::get_property_type('address'), 'Postal address', VALUE_OPTIONAL),
1033 'phone1' => new external_value(core_user::get_property_type('phone1'), 'Phone 1', VALUE_OPTIONAL),
1034 'phone2' => new external_value(core_user::get_property_type('phone2'), 'Phone 2', VALUE_OPTIONAL),
1035 'icq' => new external_value(core_user::get_property_type('icq'), 'icq number', VALUE_OPTIONAL),
1036 'skype' => new external_value(core_user::get_property_type('skype'), 'skype id', VALUE_OPTIONAL),
1037 'yahoo' => new external_value(core_user::get_property_type('yahoo'), 'yahoo id', VALUE_OPTIONAL),
1038 'aim' => new external_value(core_user::get_property_type('aim'), 'aim id', VALUE_OPTIONAL),
1039 'msn' => new external_value(core_user::get_property_type('msn'), 'msn number', VALUE_OPTIONAL),
1040 'department' => new external_value(core_user::get_property_type('department'), 'department', VALUE_OPTIONAL),
1041 'institution' => new external_value(core_user::get_property_type('institution'), 'institution', VALUE_OPTIONAL),
1042 'idnumber' => new external_value(core_user::get_property_type('idnumber'), 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
a2ed6e69 1043 'interests' => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
ac9768fc
SL
1044 'firstaccess' => new external_value(core_user::get_property_type('firstaccess'), 'first access to the site (0 if never)', VALUE_OPTIONAL),
1045 'lastaccess' => new external_value(core_user::get_property_type('lastaccess'), 'last access to the site (0 if never)', VALUE_OPTIONAL),
abc25c01 1046 'auth' => new external_value(core_user::get_property_type('auth'), 'Auth plugins include manual, ldap, etc', VALUE_OPTIONAL),
511db621 1047 'suspended' => new external_value(core_user::get_property_type('suspended'), 'Suspend user account, either false to enable user login or true to disable it', VALUE_OPTIONAL),
ac9768fc
SL
1048 'confirmed' => new external_value(core_user::get_property_type('confirmed'), 'Active user: 1 if confirmed, 0 otherwise', VALUE_OPTIONAL),
1049 'lang' => new external_value(core_user::get_property_type('lang'), 'Language code such as "en", must exist on server', VALUE_OPTIONAL),
1050 'calendartype' => new external_value(core_user::get_property_type('calendartype'), 'Calendar type such as "gregorian", must exist on server', VALUE_OPTIONAL),
1051 'theme' => new external_value(core_user::get_property_type('theme'), 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
1052 'timezone' => new external_value(core_user::get_property_type('timezone'), 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
1053 'mailformat' => new external_value(core_user::get_property_type('mailformat'), 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
1054 'description' => new external_value(core_user::get_property_type('description'), 'User profile description', VALUE_OPTIONAL),
1055 'descriptionformat' => new external_format_value(core_user::get_property_type('descriptionformat'), VALUE_OPTIONAL),
1056 'city' => new external_value(core_user::get_property_type('city'), 'Home city of the user', VALUE_OPTIONAL),
1057 'url' => new external_value(core_user::get_property_type('url'), 'URL of the user', VALUE_OPTIONAL),
1058 'country' => new external_value(core_user::get_property_type('country'), 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
a2ed6e69
SH
1059 'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version'),
1060 'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version'),
1061 'customfields' => new external_multiple_structure(
1062 new external_single_structure(
1063 array(
1064 'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
1065 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
1066 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
1067 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
1068 )
1069 ), 'User custom fields (also known as user profile fields)', VALUE_OPTIONAL),
1070 'preferences' => new external_multiple_structure(
1071 new external_single_structure(
1072 array(
1073 'name' => new external_value(PARAM_ALPHANUMEXT, 'The name of the preferences'),
1074 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
1075 )
1076 ), 'Users preferences', VALUE_OPTIONAL)
1077 );
b0365ea5
JM
1078 if (!empty($additionalfields)) {
1079 $userfields = array_merge($userfields, $additionalfields);
1080 }
1081 return new external_single_structure($userfields);
01479290 1082 }
b0365ea5 1083
9ffa4cb3
DW
1084 /**
1085 * Returns description of method parameters
1086 *
1087 * @return external_function_parameters
1088 * @since Moodle 2.6
1089 */
1090 public static function add_user_private_files_parameters() {
1091 return new external_function_parameters(
1092 array(
1093 'draftid' => new external_value(PARAM_INT, 'draft area id')
1094 )
1095 );
1096 }
1097
1098 /**
1099 * Copy files from a draft area to users private files area.
1100 *
a2ed6e69 1101 * @throws invalid_parameter_exception
9ffa4cb3
DW
1102 * @param int $draftid Id of a draft area containing files.
1103 * @return array An array of warnings
1104 * @since Moodle 2.6
1105 */
1106 public static function add_user_private_files($draftid) {
6e7bf396
JL
1107 global $CFG, $USER;
1108 require_once($CFG->libdir . "/filelib.php");
9ffa4cb3 1109
a2ed6e69 1110 $params = self::validate_parameters(self::add_user_private_files_parameters(), array('draftid' => $draftid));
9ffa4cb3
DW
1111
1112 if (isguestuser()) {
1113 throw new invalid_parameter_exception('Guest users cannot upload files');
1114 }
1115
1116 $context = context_user::instance($USER->id);
1117 require_capability('moodle/user:manageownfiles', $context);
1118
1119 $maxbytes = $CFG->userquota;
1120 $maxareabytes = $CFG->userquota;
1121 if (has_capability('moodle/user:ignoreuserquota', $context)) {
1122 $maxbytes = USER_CAN_IGNORE_FILE_SIZE_LIMITS;
1123 $maxareabytes = FILE_AREA_MAX_BYTES_UNLIMITED;
1124 }
1125
1126 $options = array('subdirs' => 1,
1127 'maxbytes' => $maxbytes,
1128 'maxfiles' => -1,
9ffa4cb3
DW
1129 'areamaxbytes' => $maxareabytes);
1130
6e7bf396 1131 file_merge_files_from_draft_area_into_filearea($draftid, $context->id, 'user', 'private', 0, $options);
9ffa4cb3
DW
1132
1133 return null;
1134 }
1135
1136 /**
1137 * Returns description of method result value
1138 *
1139 * @return external_description
1140 * @since Moodle 2.2
1141 */
1142 public static function add_user_private_files_returns() {
1143 return null;
1144 }
1145
6a403810
JL
1146 /**
1147 * Returns description of method parameters.
1148 *
1149 * @return external_function_parameters
1150 * @since Moodle 2.6
1151 */
1152 public static function add_user_device_parameters() {
1153 return new external_function_parameters(
1154 array(
1155 'appid' => new external_value(PARAM_NOTAGS, 'the app id, usually something like com.moodle.moodlemobile'),
1156 'name' => new external_value(PARAM_NOTAGS, 'the device name, \'occam\' or \'iPhone\' etc.'),
1157 'model' => new external_value(PARAM_NOTAGS, 'the device model \'Nexus4\' or \'iPad1,1\' etc.'),
1158 'platform' => new external_value(PARAM_NOTAGS, 'the device platform \'iOS\' or \'Android\' etc.'),
1159 'version' => new external_value(PARAM_NOTAGS, 'the device version \'6.1.2\' or \'4.2.2\' etc.'),
1160 'pushid' => new external_value(PARAM_RAW, 'the device PUSH token/key/identifier/registration id'),
1161 'uuid' => new external_value(PARAM_RAW, 'the device UUID')
1162 )
1163 );
1164 }
1165
1166 /**
1167 * Add a user device in Moodle database (for PUSH notifications usually).
1168 *
a2ed6e69 1169 * @throws moodle_exception
6a403810
JL
1170 * @param string $appid The app id, usually something like com.moodle.moodlemobile.
1171 * @param string $name The device name, occam or iPhone etc.
1172 * @param string $model The device model Nexus4 or iPad1.1 etc.
1173 * @param string $platform The device platform iOs or Android etc.
1174 * @param string $version The device version 6.1.2 or 4.2.2 etc.
1175 * @param string $pushid The device PUSH token/key/identifier/registration id.
1176 * @param string $uuid The device UUID.
1177 * @return array List of possible warnings.
1178 * @since Moodle 2.6
1179 */
1180 public static function add_user_device($appid, $name, $model, $platform, $version, $pushid, $uuid) {
1181 global $CFG, $USER, $DB;
1182 require_once($CFG->dirroot . "/user/lib.php");
1183
1184 $params = self::validate_parameters(self::add_user_device_parameters(),
1185 array('appid' => $appid,
1186 'name' => $name,
1187 'model' => $model,
1188 'platform' => $platform,
1189 'version' => $version,
1190 'pushid' => $pushid,
1191 'uuid' => $uuid
1192 ));
1193
1194 $warnings = array();
1195
1196 // Prevent duplicate keys for users.
1197 if ($DB->get_record('user_devices', array('pushid' => $params['pushid'], 'userid' => $USER->id))) {
1198 $warnings['warning'][] = array(
1199 'item' => $params['pushid'],
1200 'warningcode' => 'existingkeyforthisuser',
1201 'message' => 'This key is already stored for this user'
1202 );
1203 return $warnings;
1204 }
1205
4bf3a713
JL
1206 // Notice that we can have multiple devices because previously it was allowed to have repeated ones.
1207 // Since we don't have a clear way to decide which one is the more appropiate, we update all.
1208 if ($userdevices = $DB->get_records('user_devices', array('uuid' => $params['uuid'],
1209 'appid' => $params['appid'], 'userid' => $USER->id))) {
1210
1211 foreach ($userdevices as $userdevice) {
1212 $userdevice->version = $params['version']; // Maybe the user upgraded the device.
1213 $userdevice->pushid = $params['pushid'];
1214 $userdevice->timemodified = time();
1215 $DB->update_record('user_devices', $userdevice);
1216 }
1217
1218 } else {
1219 $userdevice = new stdclass;
1220 $userdevice->userid = $USER->id;
1221 $userdevice->appid = $params['appid'];
1222 $userdevice->name = $params['name'];
1223 $userdevice->model = $params['model'];
1224 $userdevice->platform = $params['platform'];
1225 $userdevice->version = $params['version'];
1226 $userdevice->pushid = $params['pushid'];
1227 $userdevice->uuid = $params['uuid'];
1228 $userdevice->timecreated = time();
1229 $userdevice->timemodified = $userdevice->timecreated;
1230
1231 if (!$DB->insert_record('user_devices', $userdevice)) {
1232 throw new moodle_exception("There was a problem saving in the database the device with key: " . $params['pushid']);
1233 }
6a403810
JL
1234 }
1235
1236 return $warnings;
1237 }
1238
1239 /**
1240 * Returns description of method result value.
1241 *
1242 * @return external_multiple_structure
1243 * @since Moodle 2.6
1244 */
1245 public static function add_user_device_returns() {
1246 return new external_multiple_structure(
1247 new external_warnings()
1248 );
1249 }
1250
3221718e
JL
1251 /**
1252 * Returns description of method parameters.
1253 *
1254 * @return external_function_parameters
1255 * @since Moodle 2.9
1256 */
1257 public static function remove_user_device_parameters() {
1258 return new external_function_parameters(
1259 array(
1260 'uuid' => new external_value(PARAM_RAW, 'the device UUID'),
1261 'appid' => new external_value(PARAM_NOTAGS,
1262 'the app id, if empty devices matching the UUID for the user will be removed',
1263 VALUE_DEFAULT, ''),
1264 )
1265 );
1266 }
1267
1268 /**
1269 * Remove a user device from the Moodle database (for PUSH notifications usually).
1270 *
1271 * @param string $uuid The device UUID.
1272 * @param string $appid The app id, opitonal parameter. If empty all the devices fmatching the UUID or the user will be removed.
1273 * @return array List of possible warnings and removal status.
1274 * @since Moodle 2.9
1275 */
1276 public static function remove_user_device($uuid, $appid = "") {
1277 global $CFG;
1278 require_once($CFG->dirroot . "/user/lib.php");
1279
1280 $params = self::validate_parameters(self::remove_user_device_parameters(), array('uuid' => $uuid, 'appid' => $appid));
1281
1282 $context = context_system::instance();
1283 self::validate_context($context);
1284
1285 // Warnings array, it can be empty at the end but is mandatory.
1286 $warnings = array();
1287
1288 $removed = user_remove_user_device($params['uuid'], $params['appid']);
1289
1290 if (!$removed) {
1291 $warnings[] = array(
1292 'item' => $params['uuid'],
1293 'warningcode' => 'devicedoesnotexist',
1294 'message' => 'The device doesn\'t exists in the database'
1295 );
1296 }
1297
1298 $result = array(
1299 'removed' => $removed,
1300 'warnings' => $warnings
1301 );
1302
1303 return $result;
1304 }
1305
1306 /**
1307 * Returns description of method result value.
1308 *
1309 * @return external_multiple_structure
1310 * @since Moodle 2.9
1311 */
1312 public static function remove_user_device_returns() {
1313 return new external_single_structure(
1314 array(
1315 'removed' => new external_value(PARAM_BOOL, 'True if removed, false if not removed because it doesn\'t exists'),
1316 'warnings' => new external_warnings(),
1317 )
1318 );
1319 }
1320
214102d0
JL
1321 /**
1322 * Returns description of method parameters
1323 *
1324 * @return external_function_parameters
1325 * @since Moodle 2.9
1326 */
1327 public static function view_user_list_parameters() {
1328 return new external_function_parameters(
1329 array(
1330 'courseid' => new external_value(PARAM_INT, 'id of the course, 0 for site')
1331 )
1332 );
1333 }
1334
1335 /**
1c2b7882 1336 * Trigger the user_list_viewed event.
214102d0
JL
1337 *
1338 * @param int $courseid id of course
1339 * @return array of warnings and status result
1340 * @since Moodle 2.9
1341 * @throws moodle_exception
1342 */
1343 public static function view_user_list($courseid) {
1344 global $CFG;
1345 require_once($CFG->dirroot . "/user/lib.php");
93b47710 1346 require_once($CFG->dirroot . '/course/lib.php');
214102d0
JL
1347
1348 $params = self::validate_parameters(self::view_user_list_parameters(),
1349 array(
1350 'courseid' => $courseid
1351 ));
1352
1353 $warnings = array();
1354
1355 if (empty($params['courseid'])) {
1356 $params['courseid'] = SITEID;
1357 }
1358
1359 $course = get_course($params['courseid']);
1360
1361 if ($course->id == SITEID) {
1362 $context = context_system::instance();
1363 } else {
1364 $context = context_course::instance($course->id);
1365 }
1366 self::validate_context($context);
1367
93b47710 1368 course_require_view_participants($context);
214102d0
JL
1369
1370 user_list_view($course, $context);
1371
1372 $result = array();
1373 $result['status'] = true;
1374 $result['warnings'] = $warnings;
1375 return $result;
1376 }
1377
1378 /**
1379 * Returns description of method result value
1380 *
1381 * @return external_description
1382 * @since Moodle 2.9
1383 */
1384 public static function view_user_list_returns() {
1385 return new external_single_structure(
1386 array(
1387 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
1388 'warnings' => new external_warnings()
1389 )
1390 );
1391 }
1392
94dcab76
JL
1393 /**
1394 * Returns description of method parameters
1395 *
1396 * @return external_function_parameters
1397 * @since Moodle 2.9
1398 */
1399 public static function view_user_profile_parameters() {
1400 return new external_function_parameters(
1401 array(
1402 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
1403 'courseid' => new external_value(PARAM_INT, 'id of the course, default site course', VALUE_DEFAULT, 0)
1404 )
1405 );
1406 }
1407
1408 /**
1c2b7882 1409 * Trigger the user profile viewed event.
94dcab76
JL
1410 *
1411 * @param int $userid id of user
1412 * @param int $courseid id of course
1413 * @return array of warnings and status result
1414 * @since Moodle 2.9
1415 * @throws moodle_exception
1416 */
1417 public static function view_user_profile($userid, $courseid = 0) {
1418 global $CFG, $USER;
1419 require_once($CFG->dirroot . "/user/profile/lib.php");
1420
1421 $params = self::validate_parameters(self::view_user_profile_parameters(),
1422 array(
1423 'userid' => $userid,
1424 'courseid' => $courseid
1425 ));
1426
1427 $warnings = array();
1428
1429 if (empty($params['userid'])) {
1430 $params['userid'] = $USER->id;
1431 }
1432
1433 if (empty($params['courseid'])) {
1434 $params['courseid'] = SITEID;
1435 }
1436
1437 $course = get_course($params['courseid']);
1438 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
4485f7c5 1439 core_user::require_active_user($user);
94dcab76
JL
1440
1441 if ($course->id == SITEID) {
1442 $coursecontext = context_system::instance();;
1443 } else {
1444 $coursecontext = context_course::instance($course->id);
1445 }
1446 self::validate_context($coursecontext);
1447
1448 $currentuser = $USER->id == $user->id;
1449 $usercontext = context_user::instance($user->id);
1450
1451 if (!$currentuser and
1452 !has_capability('moodle/user:viewdetails', $coursecontext) and
1453 !has_capability('moodle/user:viewdetails', $usercontext)) {
1454 throw new moodle_exception('cannotviewprofile');
1455 }
1456
1457 // Case like user/profile.php.
1458 if ($course->id == SITEID) {
1459 profile_view($user, $usercontext);
1460 } else {
1461 // Case like user/view.php.
48a90a21 1462 if (!$currentuser and !can_access_course($course, $user, '', true)) {
94dcab76
JL
1463 throw new moodle_exception('notenrolledprofile');
1464 }
1465
1466 profile_view($user, $coursecontext, $course);
1467 }
1468
1469 $result = array();
1470 $result['status'] = true;
1471 $result['warnings'] = $warnings;
1472 return $result;
1473 }
1474
1475 /**
1476 * Returns description of method result value
1477 *
1478 * @return external_description
1479 * @since Moodle 2.9
1480 */
1481 public static function view_user_profile_returns() {
1482 return new external_single_structure(
1483 array(
1484 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
1485 'warnings' => new external_warnings()
1486 )
1487 );
1488 }
1489
45fec983
JL
1490 /**
1491 * Returns description of method parameters
1492 *
1493 * @return external_function_parameters
1494 * @since Moodle 3.2
1495 */
1496 public static function get_user_preferences_parameters() {
1497 return new external_function_parameters(
1498 array(
1499 'name' => new external_value(PARAM_RAW, 'preference name, empty for all', VALUE_DEFAULT, ''),
1500 'userid' => new external_value(PARAM_INT, 'id of the user, default to current user', VALUE_DEFAULT, 0)
1501 )
1502 );
1503 }
1504
1505 /**
1506 * Return user preferences.
1507 *
1508 * @param string $name preference name, empty for all
1509 * @param int $userid id of the user, 0 for current user
1510 * @return array of warnings and preferences
1511 * @since Moodle 3.2
1512 * @throws moodle_exception
1513 */
1514 public static function get_user_preferences($name = '', $userid = 0) {
1515 global $USER;
1516
1517 $params = self::validate_parameters(self::get_user_preferences_parameters(),
1518 array(
1519 'name' => $name,
1520 'userid' => $userid
1521 ));
1522 $preferences = array();
1523 $warnings = array();
1524
1525 $context = context_system::instance();
1526 self::validate_context($context);
1527
1528 if (empty($params['name'])) {
1529 $name = null;
1530 }
1531 if (empty($params['userid'])) {
1532 $user = null;
1533 } else {
1534 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
1535 core_user::require_active_user($user);
1536 if ($user->id != $USER->id) {
1537 // Only admins can retrieve other users preferences.
1538 require_capability('moodle/site:config', $context);
1539 }
1540 }
1541
1542 $userpreferences = get_user_preferences($name, null, $user);
1543 // Check if we received just one preference.
1544 if (!is_array($userpreferences)) {
1545 $userpreferences = array($name => $userpreferences);
1546 }
1547
1548 foreach ($userpreferences as $name => $value) {
1549 $preferences[] = array(
1550 'name' => $name,
1551 'value' => $value,
1552 );
1553 }
1554
1555 $result = array();
1556 $result['preferences'] = $preferences;
1557 $result['warnings'] = $warnings;
1558 return $result;
1559 }
1560
1561 /**
1562 * Returns description of method result value
1563 *
1564 * @return external_description
1565 * @since Moodle 3.2
1566 */
1567 public static function get_user_preferences_returns() {
1568 return new external_single_structure(
1569 array(
1570 'preferences' => new external_multiple_structure(
1571 new external_single_structure(
1572 array(
1573 'name' => new external_value(PARAM_RAW, 'The name of the preference'),
1574 'value' => new external_value(PARAM_RAW, 'The value of the preference'),
1575 )
1576 ),
1577 'User custom fields (also known as user profile fields)'
1578 ),
1579 'warnings' => new external_warnings()
1580 )
1581 );
1582 }
d44e2e42
JL
1583
1584 /**
1585 * Returns description of method parameters
1586 *
1587 * @return external_function_parameters
1588 * @since Moodle 3.2
1589 */
1590 public static function update_picture_parameters() {
1591 return new external_function_parameters(
1592 array(
1593 'draftitemid' => new external_value(PARAM_INT, 'Id of the user draft file to use as image'),
1594 'delete' => new external_value(PARAM_BOOL, 'If we should delete the user picture', VALUE_DEFAULT, false),
1595 'userid' => new external_value(PARAM_INT, 'Id of the user, 0 for current user', VALUE_DEFAULT, 0)
1596 )
1597 );
1598 }
1599
1600 /**
1601 * Update or delete the user picture in the site
1602 *
1603 * @param int $draftitemid id of the user draft file to use as image
1604 * @param bool $delete if we should delete the user picture
1605 * @param int $userid id of the user, 0 for current user
1606 * @return array warnings and success status
1607 * @since Moodle 3.2
1608 * @throws moodle_exception
1609 */
1610 public static function update_picture($draftitemid, $delete = false, $userid = 0) {
1611 global $CFG, $USER, $PAGE;
1612
1613 $params = self::validate_parameters(
1614 self::update_picture_parameters(),
1615 array(
1616 'draftitemid' => $draftitemid,
1617 'delete' => $delete,
1618 'userid' => $userid
1619 )
1620 );
1621
1622 $context = context_system::instance();
1623 self::validate_context($context);
1624
1625 if (!empty($CFG->disableuserimages)) {
1626 throw new moodle_exception('userimagesdisabled', 'admin');
1627 }
1628
1629 if (empty($params['userid']) or $params['userid'] == $USER->id) {
1630 $user = $USER;
1631 require_capability('moodle/user:editownprofile', $context);
1632 } else {
1633 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
1634 core_user::require_active_user($user);
1635 $personalcontext = context_user::instance($user->id);
1636
1637 require_capability('moodle/user:editprofile', $personalcontext);
1638 if (is_siteadmin($user) and !is_siteadmin($USER)) { // Only admins may edit other admins.
1639 throw new moodle_exception('useradmineditadmin');
1640 }
1641 }
1642
1643 // Load the appropriate auth plugin.
1644 $userauth = get_auth_plugin($user->auth);
1645 if (is_mnet_remote_user($user) or !$userauth->can_edit_profile() or $userauth->edit_profile_url()) {
1646 throw new moodle_exception('noprofileedit', 'auth');
1647 }
1648
1649 $filemanageroptions = array('maxbytes' => $CFG->maxbytes, 'subdirs' => 0, 'maxfiles' => 1, 'accepted_types' => 'web_image');
1650 $user->deletepicture = $params['delete'];
1651 $user->imagefile = $params['draftitemid'];
1652 $success = core_user::update_picture($user, $filemanageroptions);
1653
1654 $result = array(
1655 'success' => $success,
1656 'warnings' => array(),
1657 );
1658 if ($success) {
1659 $userpicture = new user_picture(core_user::get_user($user->id));
1660 $userpicture->size = 1; // Size f1.
1661 $result['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1662 }
1663 return $result;
1664 }
1665
1666 /**
1667 * Returns description of method result value
1668 *
1669 * @return external_description
1670 * @since Moodle 3.2
1671 */
1672 public static function update_picture_returns() {
1673 return new external_single_structure(
1674 array(
1675 'success' => new external_value(PARAM_BOOL, 'True if the image was updated, false otherwise.'),
1676 'profileimageurl' => new external_value(PARAM_URL, 'New profile user image url', VALUE_OPTIONAL),
1677 'warnings' => new external_warnings()
1678 )
1679 );
1680 }
649777fb
JL
1681
1682 /**
1683 * Returns description of method parameters
1684 *
1685 * @return external_function_parameters
1686 * @since Moodle 3.2
1687 */
1688 public static function set_user_preferences_parameters() {
1689 return new external_function_parameters(
1690 array(
1691 'preferences' => new external_multiple_structure(
1692 new external_single_structure(
1693 array(
1694 'name' => new external_value(PARAM_RAW, 'The name of the preference'),
1695 'value' => new external_value(PARAM_RAW, 'The value of the preference'),
1696 'userid' => new external_value(PARAM_INT, 'Id of the user to set the preference'),
1697 )
1698 )
1699 )
1700 )
1701 );
1702 }
1703
1704 /**
1705 * Set user preferences.
1706 *
1707 * @param array $preferences list of preferences including name, value and userid
1708 * @return array of warnings and preferences saved
1709 * @since Moodle 3.2
1710 * @throws moodle_exception
1711 */
1712 public static function set_user_preferences($preferences) {
1713 global $USER;
1714
1715 $params = self::validate_parameters(self::set_user_preferences_parameters(), array('preferences' => $preferences));
1716 $warnings = array();
1717 $saved = array();
1718
1719 $context = context_system::instance();
1720 self::validate_context($context);
649777fb
JL
1721
1722 $userscache = array();
1723 foreach ($params['preferences'] as $pref) {
1724 // Check to which user set the preference.
1725 if (!empty($userscache[$pref['userid']])) {
1726 $user = $userscache[$pref['userid']];
1727 } else {
1728 try {
1729 $user = core_user::get_user($pref['userid'], '*', MUST_EXIST);
1730 core_user::require_active_user($user);
1731 $userscache[$pref['userid']] = $user;
1732 } catch (Exception $e) {
1733 $warnings[] = array(
1734 'item' => 'user',
1735 'itemid' => $pref['userid'],
1736 'warningcode' => 'invaliduser',
1737 'message' => $e->getMessage()
1738 );
1739 continue;
1740 }
1741 }
1742
1743 try {
6e65554e
MG
1744 if (core_user::can_edit_preference($pref['name'], $user)) {
1745 $value = core_user::clean_preference($pref['value'], $pref['name']);
1746 set_user_preference($pref['name'], $value, $user->id);
1747 $saved[] = array(
1748 'name' => $pref['name'],
1749 'userid' => $user->id,
1750 );
1751 } else {
1752 $warnings[] = array(
1753 'item' => 'user',
1754 'itemid' => $user->id,
1755 'warningcode' => 'nopermission',
1756 'message' => 'You are not allowed to change the preference '.s($pref['name']).' for user '.$user->id
1757 );
1758 }
649777fb
JL
1759 } catch (Exception $e) {
1760 $warnings[] = array(
1761 'item' => 'user',
1762 'itemid' => $user->id,
1763 'warningcode' => 'errorsavingpreference',
1764 'message' => $e->getMessage()
1765 );
1766 }
1767 }
1768
1769 $result = array();
1770 $result['saved'] = $saved;
1771 $result['warnings'] = $warnings;
1772 return $result;
1773 }
1774
1775 /**
1776 * Returns description of method result value
1777 *
1778 * @return external_description
1779 * @since Moodle 3.2
1780 */
1781 public static function set_user_preferences_returns() {
1782 return new external_single_structure(
1783 array(
1784 'saved' => new external_multiple_structure(
1785 new external_single_structure(
1786 array(
1787 'name' => new external_value(PARAM_RAW, 'The name of the preference'),
1788 'userid' => new external_value(PARAM_INT, 'The user the preference was set for'),
1789 )
1790 ), 'Preferences saved'
1791 ),
1792 'warnings' => new external_warnings()
1793 )
1794 );
1795 }
3e8145a3
JL
1796
1797 /**
1798 * Returns description of method parameters.
1799 *
1800 * @return external_function_parameters
1801 * @since Moodle 3.2
1802 */
1803 public static function agree_site_policy_parameters() {
1804 return new external_function_parameters(array());
1805 }
1806
1807 /**
1808 * Agree the site policy for the current user.
1809 *
1810 * @return array of warnings and status result
1811 * @since Moodle 3.2
1812 * @throws moodle_exception
1813 */
1814 public static function agree_site_policy() {
1815 global $CFG, $DB, $USER;
1816
1817 $warnings = array();
1818
1819 $context = context_system::instance();
1820 try {
1821 // We expect an exception here since the user didn't agree the site policy yet.
1822 self::validate_context($context);
1823 } catch (Exception $e) {
1824 // We are expecting only a sitepolicynotagreed exception.
1825 if (!($e instanceof moodle_exception) or $e->errorcode != 'sitepolicynotagreed') {
1826 // In case we receive a different exception, throw it.
1827 throw $e;
1828 }
1829 }
1830
1831 if (empty($CFG->sitepolicy)) {
1832 $status = false;
1833 $warnings[] = array(
1834 'item' => 'user',
1835 'itemid' => $USER->id,
1836 'warningcode' => 'nositepolicy',
1837 'message' => 'The site does not have a site policy configured.'
1838 );
1839 } else if (!empty($USER->policyagreed)) {
1840 $status = false;
1841 $warnings[] = array(
1842 'item' => 'user',
1843 'itemid' => $USER->id,
1844 'warningcode' => 'alreadyagreed',
1845 'message' => 'The user already agreed the site policy.'
1846 );
1847 } else {
1848 $DB->set_field('user', 'policyagreed', 1, array('id' => $USER->id));
1849 $USER->policyagreed = 1;
1850 $status = true;
1851 }
1852
1853 $result = array();
1854 $result['status'] = $status;
1855 $result['warnings'] = $warnings;
1856 return $result;
1857 }
1858
1859 /**
1860 * Returns description of method result value.
1861 *
1862 * @return external_description
1863 * @since Moodle 3.2
1864 */
1865 public static function agree_site_policy_returns() {
1866 return new external_single_structure(
1867 array(
1868 'status' => new external_value(PARAM_BOOL, 'Status: true only if we set the policyagreed to 1 for the user'),
1869 'warnings' => new external_warnings()
1870 )
1871 );
1872 }
f74ac6e7
JL
1873
1874 /**
1875 * Returns description of method parameters.
1876 *
1877 * @return external_function_parameters
1878 * @since Moodle 3.4
1879 */
1880 public static function get_private_files_info_parameters() {
1881 return new external_function_parameters(
1882 array(
1883 'userid' => new external_value(PARAM_INT, 'Id of the user, default to current user.', VALUE_DEFAULT, 0)
1884 )
1885 );
1886 }
1887
1888 /**
1889 * Returns general information about files in the user private files area.
1890 *
1891 * @param int $userid Id of the user, default to current user.
1892 * @return array of warnings and file area information
1893 * @since Moodle 3.4
1894 * @throws moodle_exception
1895 */
1896 public static function get_private_files_info($userid = 0) {
1897 global $CFG, $USER;
1898 require_once($CFG->libdir . '/filelib.php');
1899
1900 $params = self::validate_parameters(self::get_private_files_info_parameters(), array('userid' => $userid));
1901 $warnings = array();
1902
1903 $context = context_system::instance();
1904 self::validate_context($context);
1905
1906 if (empty($params['userid']) || $params['userid'] == $USER->id) {
1907 $usercontext = context_user::instance($USER->id);
1908 require_capability('moodle/user:manageownfiles', $usercontext);
1909 } else {
1910 $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
1911 core_user::require_active_user($user);
1912 // Only admins can retrieve other users information.
1913 require_capability('moodle/site:config', $context);
1914 $usercontext = context_user::instance($user->id);
1915 }
1916
1917 $fileareainfo = file_get_file_area_info($usercontext->id, 'user', 'private');
1918
1919 $result = array();
1920 $result['filecount'] = $fileareainfo['filecount'];
1921 $result['foldercount'] = $fileareainfo['foldercount'];
1922 $result['filesize'] = $fileareainfo['filesize'];
1923 $result['filesizewithoutreferences'] = $fileareainfo['filesize_without_references'];
1924 $result['warnings'] = $warnings;
1925 return $result;
1926 }
1927
1928 /**
1929 * Returns description of method result value.
1930 *
1931 * @return external_description
1932 * @since Moodle 3.4
1933 */
1934 public static function get_private_files_info_returns() {
1935 return new external_single_structure(
1936 array(
1937 'filecount' => new external_value(PARAM_INT, 'Number of files in the area.'),
1938 'foldercount' => new external_value(PARAM_INT, 'Number of folders in the area.'),
1939 'filesize' => new external_value(PARAM_INT, 'Total size of the files in the area.'),
1940 'filesizewithoutreferences' => new external_value(PARAM_INT, 'Total size of the area excluding file references'),
1941 'warnings' => new external_warnings()
1942 )
1943 );
1944 }
5d1017e1 1945}