MDL-45893 user_menu: fix to hide user_pictures from screen readers
[moodle.git] / user / lib.php
CommitLineData
fb79269b 1<?php
fb79269b 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 *
a2ed6e69
SH
20 * @package core_user
21 * @copyright 2009 Moodle Pty Ltd (http://moodle.com)
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
fb79269b 23 */
24
25
26/**
27 * Creates a user
adfb459c 28 *
a2ed6e69 29 * @throws moodle_exception
bb78e249
RT
30 * @param stdClass $user user to create
31 * @param bool $updatepassword if true, authentication plugin will update password.
2b55cb1b
RT
32 * @param bool $triggerevent set false if user_created event should not be triggred.
33 * This will not affect user_password_updated event triggering.
fb79269b 34 * @return int id of the newly created user
35 */
2b55cb1b 36function user_create_user($user, $updatepassword = true, $triggerevent = true) {
8bf0f207 37 global $CFG, $DB;
fb79269b 38
bb78e249 39 // Set the timecreate field to the current time.
fb79269b 40 if (!is_object($user)) {
8bf0f207 41 $user = (object) $user;
fb79269b 42 }
bd0f26bd 43
bb78e249 44 // Check username.
2f1e464a 45 if ($user->username !== core_text::strtolower($user->username)) {
45b4464c
JM
46 throw new moodle_exception('usernamelowercase');
47 } else {
48 if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
49 throw new moodle_exception('invalidusername');
50 }
51 }
52
bb78e249
RT
53 // Save the password in a temp value for later.
54 if ($updatepassword && isset($user->password)) {
adfb459c 55
bb78e249 56 // Check password toward the password policy.
adfb459c
JM
57 if (!check_password_policy($user->password, $errmsg)) {
58 throw new moodle_exception($errmsg);
59 }
60
61 $userpassword = $user->password;
62 unset($user->password);
63 }
bd0f26bd 64
8bf0f207
MN
65 // Make sure calendartype, if set, is valid.
66 if (!empty($user->calendartype)) {
67 $availablecalendartypes = \core_calendar\type_factory::get_list_of_calendar_types();
68 if (empty($availablecalendartypes[$user->calendartype])) {
69 $user->calendartype = $CFG->calendartype;
70 }
71 } else {
72 $user->calendartype = $CFG->calendartype;
73 }
74
9f7379e9
MG
75 // Apply default values for user preferences that are stored in users table.
76 if (!isset($user->maildisplay)) {
77 $user->maildisplay = $CFG->defaultpreference_maildisplay;
78 }
79 if (!isset($user->mailformat)) {
80 $user->mailformat = $CFG->defaultpreference_mailformat;
81 }
82 if (!isset($user->maildigest)) {
83 $user->maildigest = $CFG->defaultpreference_maildigest;
84 }
85 if (!isset($user->autosubscribe)) {
86 $user->autosubscribe = $CFG->defaultpreference_autosubscribe;
87 }
88 if (!isset($user->trackforums)) {
89 $user->trackforums = $CFG->defaultpreference_trackforums;
90 }
91
fb79269b 92 $user->timecreated = time();
bd0f26bd 93 $user->timemodified = $user->timecreated;
fb79269b 94
bb78e249 95 // Insert the user into the database.
fb79269b 96 $newuserid = $DB->insert_record('user', $user);
97
bb78e249
RT
98 // Create USER context for this user.
99 $usercontext = context_user::instance($newuserid);
b6dcb7d9 100
bb78e249 101 // Update user password if necessary.
adfb459c 102 if (isset($userpassword)) {
bb78e249
RT
103 // Get full database user row, in case auth is default.
104 $newuser = $DB->get_record('user', array('id' => $newuserid));
adfb459c
JM
105 $authplugin = get_auth_plugin($newuser->auth);
106 $authplugin->user_update_password($newuser, $userpassword);
107 }
108
2b55cb1b
RT
109 // Trigger event If required.
110 if ($triggerevent) {
111 \core\event\user_created::create_from_userid($newuserid)->trigger();
112 }
adfb459c 113
fb79269b 114 return $newuserid;
fb79269b 115}
116
117/**
118 * Update a user with a user object (will compare against the ID)
adfb459c 119 *
a2ed6e69 120 * @throws moodle_exception
bb78e249
RT
121 * @param stdClass $user the user to update
122 * @param bool $updatepassword if true, authentication plugin will update password.
2b55cb1b
RT
123 * @param bool $triggerevent set false if user_updated event should not be triggred.
124 * This will not affect user_password_updated event triggering.
fb79269b 125 */
2b55cb1b 126function user_update_user($user, $updatepassword = true, $triggerevent = true) {
fb79269b 127 global $DB;
bd0f26bd 128
a2ed6e69 129 // Set the timecreate field to the current time.
bd0f26bd 130 if (!is_object($user)) {
8bf0f207 131 $user = (object) $user;
bd0f26bd 132 }
adfb459c 133
a2ed6e69 134 // Check username.
45b4464c 135 if (isset($user->username)) {
2f1e464a 136 if ($user->username !== core_text::strtolower($user->username)) {
45b4464c
JM
137 throw new moodle_exception('usernamelowercase');
138 } else {
139 if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
140 throw new moodle_exception('invalidusername');
141 }
142 }
143 }
144
bb78e249
RT
145 // Unset password here, for updating later, if password update is required.
146 if ($updatepassword && isset($user->password)) {
adfb459c 147
a2ed6e69 148 // Check password toward the password policy.
adfb459c
JM
149 if (!check_password_policy($user->password, $errmsg)) {
150 throw new moodle_exception($errmsg);
151 }
152
9e63c0ff
FS
153 $passwd = $user->password;
154 unset($user->password);
155 }
bd0f26bd 156
8bf0f207
MN
157 // Make sure calendartype, if set, is valid.
158 if (!empty($user->calendartype)) {
159 $availablecalendartypes = \core_calendar\type_factory::get_list_of_calendar_types();
160 // If it doesn't exist, then unset this value, we do not want to update the user's value.
161 if (empty($availablecalendartypes[$user->calendartype])) {
162 unset($user->calendartype);
163 }
164 } else {
165 // Unset this variable, must be an empty string, which we do not want to update the calendartype to.
166 unset($user->calendartype);
167 }
168
bd0f26bd 169 $user->timemodified = time();
fb79269b 170 $DB->update_record('user', $user);
b6dcb7d9 171
bb78e249
RT
172 if ($updatepassword) {
173 // Get full user record.
174 $updateduser = $DB->get_record('user', array('id' => $user->id));
9e63c0ff 175
a2ed6e69 176 // If password was set, then update its hash.
bb78e249
RT
177 if (isset($passwd)) {
178 $authplugin = get_auth_plugin($updateduser->auth);
179 if ($authplugin->can_change_password()) {
180 $authplugin->user_update_password($updateduser, $passwd);
181 }
adfb459c
JM
182 }
183 }
2b55cb1b
RT
184 // Trigger event if required.
185 if ($triggerevent) {
186 \core\event\user_updated::create_from_userid($user->id)->trigger();
187 }
adfb459c 188}
fb79269b 189
190/**
191 * Marks user deleted in internal user database and notifies the auth plugin.
192 * Also unenrols user from all roles and does other cleanup.
193 *
194 * @todo Decide if this transaction is really needed (look for internal TODO:)
195 * @param object $user Userobject before delete (without system magic quotes)
196 * @return boolean success
197 */
198function user_delete_user($user) {
45fb2cf8 199 return delete_user($user);
fb79269b 200}
201
202/**
203 * Get users by id
fb79269b 204 *
a2ed6e69
SH
205 * @param array $userids id of users to retrieve
206 * @return array
fb79269b 207 */
208function user_get_users_by_id($userids) {
209 global $DB;
210 return $DB->get_records_list('user', 'id', $userids);
211}
b1627a92 212
61c8e0d7
FM
213/**
214 * Returns the list of default 'displayable' fields
215 *
216 * Contains database field names but also names used to generate information, such as enrolledcourses
217 *
218 * @return array of user fields
219 */
220function user_get_default_fields() {
221 return array( 'id', 'username', 'fullname', 'firstname', 'lastname', 'email',
222 'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo', 'aim', 'msn', 'department',
223 'institution', 'interests', 'firstaccess', 'lastaccess', 'auth', 'confirmed',
224 'idnumber', 'lang', 'theme', 'timezone', 'mailformat', 'description', 'descriptionformat',
225 'city', 'url', 'country', 'profileimageurlsmall', 'profileimageurl', 'customfields',
226 'groups', 'roles', 'preferences', 'enrolledcourses'
227 );
228}
01479290
DC
229
230/**
231 *
a2ed6e69 232 * Give user record from mdl_user, build an array contains all user details.
93ce0e82
JM
233 *
234 * Warning: description file urls are 'webservice/pluginfile.php' is use.
235 * it can be changed with $CFG->moodlewstextformatlinkstoimagesfile
236 *
a2ed6e69 237 * @throws moodle_exception
01479290 238 * @param stdClass $user user record from mdl_user
01479290 239 * @param stdClass $course moodle course
ad7612f5 240 * @param array $userfields required fields
d6731600 241 * @return array|null
01479290 242 */
ad7612f5 243function user_get_user_details($user, $course = null, array $userfields = array()) {
01479290 244 global $USER, $DB, $CFG;
a2ed6e69
SH
245 require_once($CFG->dirroot . "/user/profile/lib.php"); // Custom field library.
246 require_once($CFG->dirroot . "/lib/filelib.php"); // File handling on description and friends.
01479290 247
61c8e0d7 248 $defaultfields = user_get_default_fields();
ad7612f5
DC
249
250 if (empty($userfields)) {
251 $userfields = $defaultfields;
252 }
253
254 foreach ($userfields as $thefield) {
255 if (!in_array($thefield, $defaultfields)) {
256 throw new moodle_exception('invaliduserfield', 'error', '', $thefield);
257 }
258 }
259
a2ed6e69 260 // Make sure id and fullname are included.
ad7612f5
DC
261 if (!in_array('id', $userfields)) {
262 $userfields[] = 'id';
263 }
264
265 if (!in_array('fullname', $userfields)) {
266 $userfields[] = 'fullname';
267 }
268
01479290 269 if (!empty($course)) {
43731030
FM
270 $context = context_course::instance($course->id);
271 $usercontext = context_user::instance($user->id);
1e539f64 272 $canviewdetailscap = (has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext));
01479290 273 } else {
43731030 274 $context = context_user::instance($user->id);
01479290 275 $usercontext = $context;
1e539f64 276 $canviewdetailscap = has_capability('moodle/user:viewdetails', $usercontext);
01479290
DC
277 }
278
279 $currentuser = ($user->id == $USER->id);
280 $isadmin = is_siteadmin($USER);
281
48a7b182
JM
282 $showuseridentityfields = get_extra_user_fields($context);
283
01479290
DC
284 if (!empty($course)) {
285 $canviewhiddenuserfields = has_capability('moodle/course:viewhiddenuserfields', $context);
286 } else {
287 $canviewhiddenuserfields = has_capability('moodle/user:viewhiddendetails', $context);
288 }
86477112 289 $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
01479290
DC
290 if (!empty($course)) {
291 $canviewuseremail = has_capability('moodle/course:useremail', $context);
292 } else {
293 $canviewuseremail = false;
294 }
a2ed6e69 295 $cannotviewdescription = !empty($CFG->profilesforenrolledusersonly) && !$currentuser && !$DB->record_exists('role_assignments', array('userid' => $user->id));
01479290
DC
296 if (!empty($course)) {
297 $canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
298 } else {
299 $canaccessallgroups = false;
300 }
301
302 if (!$currentuser && !$canviewdetailscap && !has_coursecontact_role($user->id)) {
a2ed6e69 303 // Skip this user details.
01479290
DC
304 return null;
305 }
306
307 $userdetails = array();
308 $userdetails['id'] = $user->id;
309
ad7612f5 310 if (($isadmin or $currentuser) and in_array('username', $userfields)) {
01479290
DC
311 $userdetails['username'] = $user->username;
312 }
313 if ($isadmin or $canviewfullnames) {
ad7612f5
DC
314 if (in_array('firstname', $userfields)) {
315 $userdetails['firstname'] = $user->firstname;
316 }
317 if (in_array('lastname', $userfields)) {
318 $userdetails['lastname'] = $user->lastname;
319 }
01479290
DC
320 }
321 $userdetails['fullname'] = fullname($user);
322
ad7612f5
DC
323 if (in_array('customfields', $userfields)) {
324 $fields = $DB->get_recordset_sql("SELECT f.*
325 FROM {user_info_field} f
326 JOIN {user_info_category} c
327 ON f.categoryid=c.id
328 ORDER BY c.sortorder ASC, f.sortorder ASC");
329 $userdetails['customfields'] = array();
330 foreach ($fields as $field) {
331 require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
332 $newfield = 'profile_field_'.$field->datatype;
333 $formfield = new $newfield($field->id, $user->id);
334 if ($formfield->is_visible() and !$formfield->is_empty()) {
335 $userdetails['customfields'][] =
336 array('name' => $formfield->field->name, 'value' => $formfield->data,
337 'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
338 }
339 }
340 $fields->close();
a2ed6e69 341 // Unset customfields if it's empty.
ad7612f5
DC
342 if (empty($userdetails['customfields'])) {
343 unset($userdetails['customfields']);
01479290 344 }
01479290
DC
345 }
346
a2ed6e69 347 // Profile image.
ad7612f5 348 if (in_array('profileimageurl', $userfields)) {
a2ed6e69 349 $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', null, '/', 'f1');
ad7612f5
DC
350 $userdetails['profileimageurl'] = $profileimageurl->out(false);
351 }
352 if (in_array('profileimageurlsmall', $userfields)) {
a2ed6e69 353 $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', null, '/', 'f2');
ad7612f5
DC
354 $userdetails['profileimageurlsmall'] = $profileimageurlsmall->out(false);
355 }
01479290 356
a2ed6e69 357 // Hidden user field.
01479290
DC
358 if ($canviewhiddenuserfields) {
359 $hiddenfields = array();
a2ed6e69
SH
360 // Address, phone1 and phone2 not appears in hidden fields list but require viewhiddenfields capability
361 // according to user/profile.php.
ad7612f5 362 if ($user->address && in_array('address', $userfields)) {
01479290
DC
363 $userdetails['address'] = $user->address;
364 }
01479290
DC
365 } else {
366 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
367 }
368
48a7b182 369 if ($user->phone1 && in_array('phone1', $userfields) &&
58f739c5 370 (in_array('phone1', $showuseridentityfields) or $canviewhiddenuserfields)) {
48a7b182
JM
371 $userdetails['phone1'] = $user->phone1;
372 }
373 if ($user->phone2 && in_array('phone2', $userfields) &&
58f739c5 374 (in_array('phone2', $showuseridentityfields) or $canviewhiddenuserfields)) {
48a7b182
JM
375 $userdetails['phone2'] = $user->phone2;
376 }
377
acf64596
JM
378 if (isset($user->description) &&
379 ((!isset($hiddenfields['description']) && !$cannotviewdescription) or $isadmin)) {
380 if (in_array('description', $userfields)) {
381 // Always return the descriptionformat if description is requested.
382 list($userdetails['description'], $userdetails['descriptionformat']) =
383 external_format_text($user->description, $user->descriptionformat,
384 $usercontext->id, 'user', 'profile', null);
01479290
DC
385 }
386 }
387
ad7612f5 388 if (in_array('country', $userfields) && (!isset($hiddenfields['country']) or $isadmin) && $user->country) {
01479290
DC
389 $userdetails['country'] = $user->country;
390 }
391
ad7612f5 392 if (in_array('city', $userfields) && (!isset($hiddenfields['city']) or $isadmin) && $user->city) {
01479290
DC
393 $userdetails['city'] = $user->city;
394 }
395
ad7612f5 396 if (in_array('url', $userfields) && $user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
01479290
DC
397 $url = $user->url;
398 if (strpos($user->url, '://') === false) {
399 $url = 'http://'. $url;
400 }
401 $user->url = clean_param($user->url, PARAM_URL);
402 $userdetails['url'] = $user->url;
403 }
404
ad7612f5 405 if (in_array('icq', $userfields) && $user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
01479290
DC
406 $userdetails['icq'] = $user->icq;
407 }
408
ad7612f5 409 if (in_array('skype', $userfields) && $user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
01479290
DC
410 $userdetails['skype'] = $user->skype;
411 }
ad7612f5 412 if (in_array('yahoo', $userfields) && $user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
01479290
DC
413 $userdetails['yahoo'] = $user->yahoo;
414 }
ad7612f5 415 if (in_array('aim', $userfields) && $user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
01479290
DC
416 $userdetails['aim'] = $user->aim;
417 }
ad7612f5 418 if (in_array('msn', $userfields) && $user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
01479290
DC
419 $userdetails['msn'] = $user->msn;
420 }
421
ad7612f5 422 if (in_array('firstaccess', $userfields) && (!isset($hiddenfields['firstaccess']) or $isadmin)) {
01479290
DC
423 if ($user->firstaccess) {
424 $userdetails['firstaccess'] = $user->firstaccess;
425 } else {
426 $userdetails['firstaccess'] = 0;
427 }
428 }
ad7612f5 429 if (in_array('lastaccess', $userfields) && (!isset($hiddenfields['lastaccess']) or $isadmin)) {
01479290
DC
430 if ($user->lastaccess) {
431 $userdetails['lastaccess'] = $user->lastaccess;
432 } else {
433 $userdetails['lastaccess'] = 0;
434 }
435 }
436
a2ed6e69
SH
437 if (in_array('email', $userfields) && ($isadmin // The admin is allowed the users email.
438 or $currentuser // Of course the current user is as well.
439 or $canviewuseremail // This is a capability in course context, it will be false in usercontext.
58f739c5 440 or in_array('email', $showuseridentityfields)
01479290 441 or $user->maildisplay == 1
ca774c94 442 or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
90e30b96 443 $userdetails['email'] = $user->email;
01479290
DC
444 }
445
ad7612f5 446 if (in_array('interests', $userfields) && !empty($CFG->usetags)) {
01479290
DC
447 require_once($CFG->dirroot . '/tag/lib.php');
448 if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
449 $userdetails['interests'] = $interests;
450 }
451 }
452
a2ed6e69 453 // Departement/Institution/Idnumber are not displayed on any profile, however you can get them from editing profile.
58f739c5 454 if ($isadmin or $currentuser or in_array('idnumber', $showuseridentityfields)) {
48a7b182 455 if (in_array('idnumber', $userfields) && $user->idnumber) {
3a3f3b22
CW
456 $userdetails['idnumber'] = $user->idnumber;
457 }
48a7b182 458 }
58f739c5 459 if ($isadmin or $currentuser or in_array('institution', $showuseridentityfields)) {
ad7612f5 460 if (in_array('institution', $userfields) && $user->institution) {
01479290
DC
461 $userdetails['institution'] = $user->institution;
462 }
48a7b182 463 }
58f739c5 464 if ($isadmin or $currentuser or in_array('department', $showuseridentityfields)) {
a2ed6e69 465 if (in_array('department', $userfields) && isset($user->department)) { // Isset because it's ok to have department 0.
01479290
DC
466 $userdetails['department'] = $user->department;
467 }
468 }
469
ad7612f5 470 if (in_array('roles', $userfields) && !empty($course)) {
a2ed6e69 471 // Not a big secret.
01479290
DC
472 $roles = get_user_roles($context, $user->id, false);
473 $userdetails['roles'] = array();
474 foreach ($roles as $role) {
475 $userdetails['roles'][] = array(
476 'roleid' => $role->roleid,
477 'name' => $role->name,
478 'shortname' => $role->shortname,
479 'sortorder' => $role->sortorder
480 );
481 }
482 }
483
a2ed6e69 484 // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group.
ad7612f5 485 if (in_array('groups', $userfields) && !empty($course) && $canaccessallgroups) {
93ce0e82
JM
486 $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid,
487 'g.id, g.name,g.description,g.descriptionformat');
01479290
DC
488 $userdetails['groups'] = array();
489 foreach ($usergroups as $group) {
93ce0e82
JM
490 list($group->description, $group->descriptionformat) =
491 external_format_text($group->description, $group->descriptionformat,
492 $context->id, 'group', 'description', $group->id);
a2ed6e69
SH
493 $userdetails['groups'][] = array('id' => $group->id, 'name' => $group->name,
494 'description' => $group->description, 'descriptionformat' => $group->descriptionformat);
01479290
DC
495 }
496 }
a2ed6e69 497 // List of courses where the user is enrolled.
ad7612f5 498 if (in_array('enrolledcourses', $userfields) && !isset($hiddenfields['mycourses'])) {
01479290
DC
499 $enrolledcourses = array();
500 if ($mycourses = enrol_get_users_courses($user->id, true)) {
501 foreach ($mycourses as $mycourse) {
502 if ($mycourse->category) {
43731030 503 $coursecontext = context_course::instance($mycourse->id);
01479290
DC
504 $enrolledcourse = array();
505 $enrolledcourse['id'] = $mycourse->id;
43ff71a0 506 $enrolledcourse['fullname'] = format_string($mycourse->fullname, true, array('context' => $coursecontext));
8ebbb06a 507 $enrolledcourse['shortname'] = format_string($mycourse->shortname, true, array('context' => $coursecontext));
01479290
DC
508 $enrolledcourses[] = $enrolledcourse;
509 }
510 }
511 $userdetails['enrolledcourses'] = $enrolledcourses;
512 }
513 }
514
a2ed6e69 515 // User preferences.
ad7612f5 516 if (in_array('preferences', $userfields) && $currentuser) {
01479290
DC
517 $preferences = array();
518 $userpreferences = get_user_preferences();
a2ed6e69 519 foreach ($userpreferences as $prefname => $prefvalue) {
01479290 520 $preferences[] = array('name' => $prefname, 'value' => $prefvalue);
a2ed6e69
SH
521 }
522 $userdetails['preferences'] = $preferences;
01479290 523 }
ad7612f5 524
01479290
DC
525 return $userdetails;
526}
527
86477112
FS
528/**
529 * Tries to obtain user details, either recurring directly to the user's system profile
c70b9853 530 * or through one of the user's course enrollments (course profile).
86477112 531 *
a2ed6e69 532 * @param stdClass $user The user.
c70b9853 533 * @return array if unsuccessful or the allowed user details.
86477112
FS
534 */
535function user_get_user_details_courses($user) {
536 global $USER;
537 $userdetails = null;
538
a2ed6e69 539 // Get the courses that the user is enrolled in (only active).
86477112
FS
540 $courses = enrol_get_users_courses($user->id, true);
541
c70b9853
JM
542 $systemprofile = false;
543 if (can_view_user_details_cap($user) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
544 $systemprofile = true;
545 }
86477112 546
c70b9853 547 // Try using system profile.
86477112
FS
548 if ($systemprofile) {
549 $userdetails = user_get_user_details($user, null);
550 } else {
c70b9853 551 // Try through course profile.
86477112 552 foreach ($courses as $course) {
854859e1 553 if (can_view_user_details_cap($user, $course) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
86477112
FS
554 $userdetails = user_get_user_details($user, $course);
555 }
556 }
557 }
558
559 return $userdetails;
560}
561
562/**
c70b9853
JM
563 * Check if $USER have the necessary capabilities to obtain user details.
564 *
a2ed6e69
SH
565 * @param stdClass $user
566 * @param stdClass $course if null then only consider system profile otherwise also consider the course's profile.
c70b9853 567 * @return bool true if $USER can view user details.
86477112
FS
568 */
569function can_view_user_details_cap($user, $course = null) {
c70b9853 570 // Check $USER has the capability to view the user details at user context.
bea86e84 571 $usercontext = context_user::instance($user->id);
c70b9853
JM
572 $result = has_capability('moodle/user:viewdetails', $usercontext);
573 // Otherwise can $USER see them at course context.
574 if (!$result && !empty($course)) {
bea86e84 575 $context = context_course::instance($course->id);
c70b9853 576 $result = has_capability('moodle/user:viewdetails', $context);
86477112
FS
577 }
578 return $result;
579}
580
b1627a92
DC
581/**
582 * Return a list of page types
583 * @param string $pagetype current page type
584 * @param stdClass $parentcontext Block's parent context
585 * @param stdClass $currentcontext Current context of block
a2ed6e69 586 * @return array
b1627a92 587 */
b38e2e28 588function user_page_type_list($pagetype, $parentcontext, $currentcontext) {
a2ed6e69 589 return array('user-profile' => get_string('page-user-profile', 'pagetype'));
d6731600 590}
52dc1de7
AA
591
592/**
593 * Count the number of failed login attempts for the given user, since last successful login.
594 *
595 * @param int|stdclass $user user id or object.
596 * @param bool $reset Resets failed login count, if set to true.
597 *
598 * @return int number of failed login attempts since the last successful login.
599 */
600function user_count_login_failures($user, $reset = true) {
601 global $DB;
602
603 if (!is_object($user)) {
604 $user = $DB->get_record('user', array('id' => $user), '*', MUST_EXIST);
605 }
606 if ($user->deleted) {
607 // Deleted user, nothing to do.
608 return 0;
609 }
610 $count = get_user_preferences('login_failed_count_since_success', 0, $user);
611 if ($reset) {
612 set_user_preference('login_failed_count_since_success', 0, $user);
613 }
614 return $count;
615}
616
d24b8e52
JC
617/**
618 * Get a list of essential user navigation items.
619 *
620 * @param stdclass $user user object.
621 * @param moodle_page $page page object.
622 * @return stdClass $returnobj navigation information object, where:
623 *
624 * $returnobj->navitems array array of links where each link is a
625 * stdClass with fields url, title, and
626 * pix
627 * $returnobj->metadata array array of useful user metadata to be
628 * used when constructing navigation;
629 * fields include:
630 *
631 * ROLE FIELDS
632 * asotherrole bool whether viewing as another role
633 * rolename string name of the role
634 *
635 * USER FIELDS
636 * These fields are for the currently-logged in user, or for
637 * the user that the real user is currently logged in as.
638 *
639 * userid int the id of the user in question
640 * userfullname string the user's full name
641 * userprofileurl moodle_url the url of the user's profile
642 * useravatar string a HTML fragment - the rendered
643 * user_picture for this user
644 *
645 * "REAL USER" FIELDS
646 * These fields are for when asotheruser is true, and
647 * correspond to the underlying "real user".
648 *
649 * asotheruser bool whether viewing as another user
650 * realuserid int the id of the user in question
651 * realuserfullname string the user's full name
652 * realuserprofileurl moodle_url the url of the user's profile
653 * realuseravatar string a HTML fragment - the rendered
654 * user_picture for this user
655 *
656 * MNET PROVIDER FIELDS
657 * asmnetuser bool whether viewing as a user from an
658 * MNet provider
659 * mnetidprovidername string name of the MNet provider
660 * mnetidproviderwwwroot string URL of the MNet provider
661 */
662function user_get_user_navigation_info($user, $page) {
663 global $OUTPUT, $DB;
664
665 $returnobject = new stdClass();
666 $returnobject->navitems = array();
667 $returnobject->metadata = array();
668
669 $course = $page->course;
670
671 // Query the environment.
672 $context = context_course::instance($course->id);
673
674 // Get basic user metadata.
675 $returnobject->metadata['userid'] = $user->id;
676 $returnobject->metadata['userfullname'] = fullname($user, true);
677 $returnobject->metadata['userprofileurl'] = new moodle_url('/user/profile.php', array(
678 'id' => $user->id
679 ));
dc4bff32
JC
680 $returnobject->metadata['useravatar'] = $OUTPUT->user_picture (
681 $user,
682 array(
683 'link' => false,
684 'visibletoscreenreaders' => false
685 )
686 );
d24b8e52
JC
687 if (isguestuser()) {
688
689 // Build a list of items for a guest.
690 $login = new stdClass();
c8398fb9 691 $login->url = new moodle_url(get_login_url());
d24b8e52 692 $login->title = get_string('login');
c8398fb9 693 // TODO MDL-47457: we should be setting a login icon here.
d24b8e52
JC
694 $returnobject->navitems[] = $login;
695
696 } else {
697 // Build a list of items for a regular user.
698
699 // Query MNet status.
700 if ($returnobject->metadata['asmnetuser'] = is_mnet_remote_user($user)) {
701 $mnetidprovider = $DB->get_record('mnet_host', array('id' => $user->mnethostid));
702 $returnobject->metadata['mnetidprovidername'] = $mnetidprovider->name;
703 $returnobject->metadata['mnetidproviderwwwroot'] = $mnetidprovider->wwwroot;
704 }
705
706 // Links: My Profile.
707 $myprofile = new stdClass();
708 $myprofile->url = new moodle_url('/user/profile.php', array('id' => $user->id));
709 $myprofile->title = get_string('myprofile');
710 $myprofile->pix = "i/user";
711 $returnobject->navitems[] = $myprofile;
712
713 // Links: My Home.
714 $myhome = new stdClass();
715 $myhome->url = new moodle_url('/my/');
716 $myhome->title = get_string('mymoodle', 'admin');
717 $myhome->pix = "i/course";
718 $returnobject->navitems[] = $myhome;
719
720 // Links: Role-return or logout link.
721 $lastobj = null;
722 $buildlogout = true;
723 $returnobject->metadata['asotherrole'] = false;
724 if (is_role_switched($course->id)) {
725 if ($role = $DB->get_record('role', array('id' => $user->access['rsw'][$context->path]))) {
726 // Build role-return link instead of logout link.
727 $rolereturn = new stdClass();
728 $rolereturn->url = new moodle_url('/course/switchrole.php', array(
729 'id' => $course->id,
730 'sesskey' => sesskey(),
731 'switchrole' => 0,
732 'returnurl' => $PAGE->url->out_as_local_url(false)
733 ));
734 $rolereturn->pix = "a/logout";
735 $rolereturn->title = get_string('switchrolereturn');
736 $lastobj = $rolereturn;
737
738 $returnobject->metadata['asotherrole'] = true;
739 $returnobject->metadata['rolename'] = role_get_name($role, $context);
740
741 $buildlogout = false;
742 }
743 }
744
745 if ($returnobject->metadata['asotheruser'] = \core\session\manager::is_loggedinas()) {
746 $realuser = \core\session\manager::get_realuser();
747
748 // Save values for the real user, as $user will be full of data for the
749 // user the user is disguised as.
750 $returnobject->metadata['realuserid'] = $realuser->id;
751 $returnobject->metadata['realuserfullname'] = fullname($realuser, true);
752 $returnobject->metadata['realuserprofileurl'] = new moodle_url('/user/profile.php', array(
753 'id' => $realuser->id
754 ));
dc4bff32
JC
755 $returnobject->metadata['realuseravatar'] = $OUTPUT->user_picture (
756 $realuser,
757 array(
758 'link' => false,
759 'visibletoscreenreaders' => false
760 )
761 );
d24b8e52
JC
762
763 // Build a user-revert link.
764 $userrevert = new stdClass();
765 $userrevert->url = new moodle_url('/course/loginas.php', array(
766 'id' => $course->id,
767 'sesskey' => sesskey()
768 ));
769 $userrevert->pix = "a/logout";
770 $userrevert->title = get_string('userrevert');
771 $lastobj = $userrevert;
772
773 $buildlogout = false;
774 }
775
776 if ($buildlogout) {
777 // Build a logout link.
778 $logout = new stdClass();
779 $logout->url = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
780 $logout->pix = "a/logout";
781 $logout->title = get_string('logout');
782 $lastobj = $logout;
783 }
784
785 // Add the last item to the list.
786 if (!is_null($lastobj)) {
787 $returnobject->navitems[] = $lastobj;
788 }
789 }
790
791 return $returnobject;
792}