Merge branch 'int_install' of https://github.com/skodak/moodle
[moodle.git] / user / lib.php
blob7ab6c0d2ab596c44233894608c5bbd64d31019d8
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * External user API
21 * @package moodlecore
22 * @subpackage user
23 * @copyright 2009 Moodle Pty Ltd (http://moodle.com)
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28 /**
29 * Creates a user
31 * @param stdClass $user user to create
32 * @param bool $updatepassword if true, authentication plugin will update password.
33 * @return int id of the newly created user
35 function user_create_user($user, $updatepassword = true) {
36 global $DB;
38 // Set the timecreate field to the current time.
39 if (!is_object($user)) {
40 $user = (object)$user;
43 // Check username.
44 if ($user->username !== core_text::strtolower($user->username)) {
45 throw new moodle_exception('usernamelowercase');
46 } else {
47 if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
48 throw new moodle_exception('invalidusername');
52 // Save the password in a temp value for later.
53 if ($updatepassword && isset($user->password)) {
55 // Check password toward the password policy.
56 if (!check_password_policy($user->password, $errmsg)) {
57 throw new moodle_exception($errmsg);
60 $userpassword = $user->password;
61 unset($user->password);
64 $user->timecreated = time();
65 $user->timemodified = $user->timecreated;
67 // Insert the user into the database.
68 $newuserid = $DB->insert_record('user', $user);
70 // Create USER context for this user.
71 $usercontext = context_user::instance($newuserid);
73 // Update user password if necessary.
74 if (isset($userpassword)) {
75 // Get full database user row, in case auth is default.
76 $newuser = $DB->get_record('user', array('id' => $newuserid));
77 $authplugin = get_auth_plugin($newuser->auth);
78 $authplugin->user_update_password($newuser, $userpassword);
81 // Trigger event.
82 $event = \core\event\user_created::create(
83 array(
84 'objectid' => $newuserid,
85 'context' => $usercontext
88 $event->trigger();
90 return $newuserid;
93 /**
94 * Update a user with a user object (will compare against the ID)
96 * @param stdClass $user the user to update
97 * @param bool $updatepassword if true, authentication plugin will update password.
99 function user_update_user($user, $updatepassword = true) {
100 global $DB;
102 // set the timecreate field to the current time
103 if (!is_object($user)) {
104 $user = (object)$user;
107 //check username
108 if (isset($user->username)) {
109 if ($user->username !== core_text::strtolower($user->username)) {
110 throw new moodle_exception('usernamelowercase');
111 } else {
112 if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
113 throw new moodle_exception('invalidusername');
118 // Unset password here, for updating later, if password update is required.
119 if ($updatepassword && isset($user->password)) {
121 //check password toward the password policy
122 if (!check_password_policy($user->password, $errmsg)) {
123 throw new moodle_exception($errmsg);
126 $passwd = $user->password;
127 unset($user->password);
130 $user->timemodified = time();
131 $DB->update_record('user', $user);
133 if ($updatepassword) {
134 // Get full user record.
135 $updateduser = $DB->get_record('user', array('id' => $user->id));
137 // if password was set, then update its hash
138 if (isset($passwd)) {
139 $authplugin = get_auth_plugin($updateduser->auth);
140 if ($authplugin->can_change_password()) {
141 $authplugin->user_update_password($updateduser, $passwd);
146 // Trigger event.
147 $event = \core\event\user_updated::create(
148 array(
149 'objectid' => $user->id,
150 'context' => context_user::instance($user->id)
153 $event->trigger();
157 * Marks user deleted in internal user database and notifies the auth plugin.
158 * Also unenrols user from all roles and does other cleanup.
160 * @todo Decide if this transaction is really needed (look for internal TODO:)
161 * @param object $user Userobject before delete (without system magic quotes)
162 * @return boolean success
164 function user_delete_user($user) {
165 return delete_user($user);
169 * Get users by id
170 * @param array $userids id of users to retrieve
173 function user_get_users_by_id($userids) {
174 global $DB;
175 return $DB->get_records_list('user', 'id', $userids);
179 * Returns the list of default 'displayable' fields
181 * Contains database field names but also names used to generate information, such as enrolledcourses
183 * @return array of user fields
185 function user_get_default_fields() {
186 return array( 'id', 'username', 'fullname', 'firstname', 'lastname', 'email',
187 'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo', 'aim', 'msn', 'department',
188 'institution', 'interests', 'firstaccess', 'lastaccess', 'auth', 'confirmed',
189 'idnumber', 'lang', 'theme', 'timezone', 'mailformat', 'description', 'descriptionformat',
190 'city', 'url', 'country', 'profileimageurlsmall', 'profileimageurl', 'customfields',
191 'groups', 'roles', 'preferences', 'enrolledcourses'
197 * Give user record from mdl_user, build an array conntains
198 * all user details
200 * Warning: description file urls are 'webservice/pluginfile.php' is use.
201 * it can be changed with $CFG->moodlewstextformatlinkstoimagesfile
203 * @param stdClass $user user record from mdl_user
204 * @param stdClass $context context object
205 * @param stdClass $course moodle course
206 * @param array $userfields required fields
207 * @return array|null
209 function user_get_user_details($user, $course = null, array $userfields = array()) {
210 global $USER, $DB, $CFG;
211 require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
212 require_once($CFG->dirroot . "/lib/filelib.php"); // file handling on description and friends
214 $defaultfields = user_get_default_fields();
216 if (empty($userfields)) {
217 $userfields = $defaultfields;
220 foreach ($userfields as $thefield) {
221 if (!in_array($thefield, $defaultfields)) {
222 throw new moodle_exception('invaliduserfield', 'error', '', $thefield);
227 // Make sure id and fullname are included
228 if (!in_array('id', $userfields)) {
229 $userfields[] = 'id';
232 if (!in_array('fullname', $userfields)) {
233 $userfields[] = 'fullname';
236 if (!empty($course)) {
237 $context = context_course::instance($course->id);
238 $usercontext = context_user::instance($user->id);
239 $canviewdetailscap = (has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext));
240 } else {
241 $context = context_user::instance($user->id);
242 $usercontext = $context;
243 $canviewdetailscap = has_capability('moodle/user:viewdetails', $usercontext);
246 $currentuser = ($user->id == $USER->id);
247 $isadmin = is_siteadmin($USER);
249 $showuseridentityfields = get_extra_user_fields($context);
251 if (!empty($course)) {
252 $canviewhiddenuserfields = has_capability('moodle/course:viewhiddenuserfields', $context);
253 } else {
254 $canviewhiddenuserfields = has_capability('moodle/user:viewhiddendetails', $context);
256 $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
257 if (!empty($course)) {
258 $canviewuseremail = has_capability('moodle/course:useremail', $context);
259 } else {
260 $canviewuseremail = false;
262 $cannotviewdescription = !empty($CFG->profilesforenrolledusersonly) && !$currentuser && !$DB->record_exists('role_assignments', array('userid'=>$user->id));
263 if (!empty($course)) {
264 $canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
265 } else {
266 $canaccessallgroups = false;
269 if (!$currentuser && !$canviewdetailscap && !has_coursecontact_role($user->id)) {
270 // skip this user details
271 return null;
274 $userdetails = array();
275 $userdetails['id'] = $user->id;
277 if (($isadmin or $currentuser) and in_array('username', $userfields)) {
278 $userdetails['username'] = $user->username;
280 if ($isadmin or $canviewfullnames) {
281 if (in_array('firstname', $userfields)) {
282 $userdetails['firstname'] = $user->firstname;
284 if (in_array('lastname', $userfields)) {
285 $userdetails['lastname'] = $user->lastname;
288 $userdetails['fullname'] = fullname($user);
290 if (in_array('customfields', $userfields)) {
291 $fields = $DB->get_recordset_sql("SELECT f.*
292 FROM {user_info_field} f
293 JOIN {user_info_category} c
294 ON f.categoryid=c.id
295 ORDER BY c.sortorder ASC, f.sortorder ASC");
296 $userdetails['customfields'] = array();
297 foreach ($fields as $field) {
298 require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
299 $newfield = 'profile_field_'.$field->datatype;
300 $formfield = new $newfield($field->id, $user->id);
301 if ($formfield->is_visible() and !$formfield->is_empty()) {
302 $userdetails['customfields'][] =
303 array('name' => $formfield->field->name, 'value' => $formfield->data,
304 'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
307 $fields->close();
308 // unset customfields if it's empty
309 if (empty($userdetails['customfields'])) {
310 unset($userdetails['customfields']);
314 // profile image
315 if (in_array('profileimageurl', $userfields)) {
316 $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f1');
317 $userdetails['profileimageurl'] = $profileimageurl->out(false);
319 if (in_array('profileimageurlsmall', $userfields)) {
320 $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f2');
321 $userdetails['profileimageurlsmall'] = $profileimageurlsmall->out(false);
324 //hidden user field
325 if ($canviewhiddenuserfields) {
326 $hiddenfields = array();
327 // address, phone1 and phone2 not appears in hidden fields list
328 // but require viewhiddenfields capability
329 // according to user/profile.php
330 if ($user->address && in_array('address', $userfields)) {
331 $userdetails['address'] = $user->address;
333 } else {
334 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
337 if ($user->phone1 && in_array('phone1', $userfields) &&
338 (in_array('phone1', $showuseridentityfields) or $canviewhiddenuserfields)) {
339 $userdetails['phone1'] = $user->phone1;
341 if ($user->phone2 && in_array('phone2', $userfields) &&
342 (in_array('phone2', $showuseridentityfields) or $canviewhiddenuserfields)) {
343 $userdetails['phone2'] = $user->phone2;
346 if (isset($user->description) &&
347 ((!isset($hiddenfields['description']) && !$cannotviewdescription) or $isadmin)) {
348 if (in_array('description', $userfields)) {
349 // Always return the descriptionformat if description is requested.
350 list($userdetails['description'], $userdetails['descriptionformat']) =
351 external_format_text($user->description, $user->descriptionformat,
352 $usercontext->id, 'user', 'profile', null);
356 if (in_array('country', $userfields) && (!isset($hiddenfields['country']) or $isadmin) && $user->country) {
357 $userdetails['country'] = $user->country;
360 if (in_array('city', $userfields) && (!isset($hiddenfields['city']) or $isadmin) && $user->city) {
361 $userdetails['city'] = $user->city;
364 if (in_array('url', $userfields) && $user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
365 $url = $user->url;
366 if (strpos($user->url, '://') === false) {
367 $url = 'http://'. $url;
369 $user->url = clean_param($user->url, PARAM_URL);
370 $userdetails['url'] = $user->url;
373 if (in_array('icq', $userfields) && $user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
374 $userdetails['icq'] = $user->icq;
377 if (in_array('skype', $userfields) && $user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
378 $userdetails['skype'] = $user->skype;
380 if (in_array('yahoo', $userfields) && $user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
381 $userdetails['yahoo'] = $user->yahoo;
383 if (in_array('aim', $userfields) && $user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
384 $userdetails['aim'] = $user->aim;
386 if (in_array('msn', $userfields) && $user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
387 $userdetails['msn'] = $user->msn;
390 if (in_array('firstaccess', $userfields) && (!isset($hiddenfields['firstaccess']) or $isadmin)) {
391 if ($user->firstaccess) {
392 $userdetails['firstaccess'] = $user->firstaccess;
393 } else {
394 $userdetails['firstaccess'] = 0;
397 if (in_array('lastaccess', $userfields) && (!isset($hiddenfields['lastaccess']) or $isadmin)) {
398 if ($user->lastaccess) {
399 $userdetails['lastaccess'] = $user->lastaccess;
400 } else {
401 $userdetails['lastaccess'] = 0;
405 if (in_array('email', $userfields) && ($isadmin // The admin is allowed the users email
406 or $currentuser // Of course the current user is as well
407 or $canviewuseremail // this is a capability in course context, it will be false in usercontext
408 or in_array('email', $showuseridentityfields)
409 or $user->maildisplay == 1
410 or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
411 $userdetails['email'] = $user->email;
414 if (in_array('interests', $userfields) && !empty($CFG->usetags)) {
415 require_once($CFG->dirroot . '/tag/lib.php');
416 if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
417 $userdetails['interests'] = $interests;
421 //Departement/Institution/Idnumber are not displayed on any profile, however you can get them from editing profile.
422 if ($isadmin or $currentuser or in_array('idnumber', $showuseridentityfields)) {
423 if (in_array('idnumber', $userfields) && $user->idnumber) {
424 $userdetails['idnumber'] = $user->idnumber;
427 if ($isadmin or $currentuser or in_array('institution', $showuseridentityfields)) {
428 if (in_array('institution', $userfields) && $user->institution) {
429 $userdetails['institution'] = $user->institution;
432 if ($isadmin or $currentuser or in_array('department', $showuseridentityfields)) {
433 if (in_array('department', $userfields) && isset($user->department)) { //isset because it's ok to have department 0
434 $userdetails['department'] = $user->department;
438 if (in_array('roles', $userfields) && !empty($course)) {
439 // not a big secret
440 $roles = get_user_roles($context, $user->id, false);
441 $userdetails['roles'] = array();
442 foreach ($roles as $role) {
443 $userdetails['roles'][] = array(
444 'roleid' => $role->roleid,
445 'name' => $role->name,
446 'shortname' => $role->shortname,
447 'sortorder' => $role->sortorder
452 // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group
453 if (in_array('groups', $userfields) && !empty($course) && $canaccessallgroups) {
454 $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid,
455 'g.id, g.name,g.description,g.descriptionformat');
456 $userdetails['groups'] = array();
457 foreach ($usergroups as $group) {
458 list($group->description, $group->descriptionformat) =
459 external_format_text($group->description, $group->descriptionformat,
460 $context->id, 'group', 'description', $group->id);
461 $userdetails['groups'][] = array('id'=>$group->id, 'name'=>$group->name,
462 'description'=>$group->description, 'descriptionformat'=>$group->descriptionformat);
465 //list of courses where the user is enrolled
466 if (in_array('enrolledcourses', $userfields) && !isset($hiddenfields['mycourses'])) {
467 $enrolledcourses = array();
468 if ($mycourses = enrol_get_users_courses($user->id, true)) {
469 foreach ($mycourses as $mycourse) {
470 if ($mycourse->category) {
471 $coursecontext = context_course::instance($mycourse->id);
472 $enrolledcourse = array();
473 $enrolledcourse['id'] = $mycourse->id;
474 $enrolledcourse['fullname'] = format_string($mycourse->fullname, true, array('context' => $coursecontext));
475 $enrolledcourse['shortname'] = format_string($mycourse->shortname, true, array('context' => $coursecontext));
476 $enrolledcourses[] = $enrolledcourse;
479 $userdetails['enrolledcourses'] = $enrolledcourses;
483 //user preferences
484 if (in_array('preferences', $userfields) && $currentuser) {
485 $preferences = array();
486 $userpreferences = get_user_preferences();
487 foreach($userpreferences as $prefname => $prefvalue) {
488 $preferences[] = array('name' => $prefname, 'value' => $prefvalue);
490 $userdetails['preferences'] = $preferences;
493 return $userdetails;
497 * Tries to obtain user details, either recurring directly to the user's system profile
498 * or through one of the user's course enrollments (course profile).
500 * @param object $user The user.
501 * @return array if unsuccessful or the allowed user details.
503 function user_get_user_details_courses($user) {
504 global $USER;
505 $userdetails = null;
507 // Get the courses that the user is enrolled in (only active).
508 $courses = enrol_get_users_courses($user->id, true);
510 $systemprofile = false;
511 if (can_view_user_details_cap($user) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
512 $systemprofile = true;
515 // Try using system profile.
516 if ($systemprofile) {
517 $userdetails = user_get_user_details($user, null);
518 } else {
519 // Try through course profile.
520 foreach ($courses as $course) {
521 if ($can_view_user_details_cap($user, $course) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
522 $userdetails = user_get_user_details($user, $course);
527 return $userdetails;
531 * Check if $USER have the necessary capabilities to obtain user details.
533 * @param object $user
534 * @param object $course if null then only consider system profile otherwise also consider the course's profile.
535 * @return bool true if $USER can view user details.
537 function can_view_user_details_cap($user, $course = null) {
538 // Check $USER has the capability to view the user details at user context.
539 $usercontext = context_user::instance($user->id);
540 $result = has_capability('moodle/user:viewdetails', $usercontext);
541 // Otherwise can $USER see them at course context.
542 if (!$result && !empty($course)) {
543 $context = context_course::instance($course->id);
544 $result = has_capability('moodle/user:viewdetails', $context);
546 return $result;
550 * Return a list of page types
551 * @param string $pagetype current page type
552 * @param stdClass $parentcontext Block's parent context
553 * @param stdClass $currentcontext Current context of block
555 function user_page_type_list($pagetype, $parentcontext, $currentcontext) {
556 return array('user-profile'=>get_string('page-user-profile', 'pagetype'));