MDL-42932 core_calendar: introduced calendar type system setting
[moodle.git] / user / lib.php
blobfe7d3385898665249109694d8d5239e8c9fb6705
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 // Make sure calendartype, if set, is valid.
65 if (!empty($user->calendartype)) {
66 $availablecalendartypes = \core_calendar\type_factory::get_list_of_calendar_types();
67 if (empty($availablecalendartypes[$user->calendartype])) {
68 $user->calendartype = $CFG->calendartype;
70 } else {
71 $user->calendartype = $CFG->calendartype;
74 $user->timecreated = time();
75 $user->timemodified = $user->timecreated;
77 // Insert the user into the database.
78 $newuserid = $DB->insert_record('user', $user);
80 // Create USER context for this user.
81 $usercontext = context_user::instance($newuserid);
83 // Update user password if necessary.
84 if (isset($userpassword)) {
85 // Get full database user row, in case auth is default.
86 $newuser = $DB->get_record('user', array('id' => $newuserid));
87 $authplugin = get_auth_plugin($newuser->auth);
88 $authplugin->user_update_password($newuser, $userpassword);
91 // Trigger event.
92 $event = \core\event\user_created::create(
93 array(
94 'objectid' => $newuserid,
95 'context' => $usercontext
98 $event->trigger();
100 return $newuserid;
104 * Update a user with a user object (will compare against the ID)
106 * @param stdClass $user the user to update
107 * @param bool $updatepassword if true, authentication plugin will update password.
109 function user_update_user($user, $updatepassword = true) {
110 global $DB;
112 // set the timecreate field to the current time
113 if (!is_object($user)) {
114 $user = (object)$user;
117 //check username
118 if (isset($user->username)) {
119 if ($user->username !== core_text::strtolower($user->username)) {
120 throw new moodle_exception('usernamelowercase');
121 } else {
122 if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
123 throw new moodle_exception('invalidusername');
128 // Unset password here, for updating later, if password update is required.
129 if ($updatepassword && isset($user->password)) {
131 //check password toward the password policy
132 if (!check_password_policy($user->password, $errmsg)) {
133 throw new moodle_exception($errmsg);
136 $passwd = $user->password;
137 unset($user->password);
140 // Make sure calendartype, if set, is valid.
141 if (!empty($user->calendartype)) {
142 $availablecalendartypes = \core_calendar\type_factory::get_list_of_calendar_types();
143 // If it doesn't exist, then unset this value, we do not want to update the user's value.
144 if (empty($availablecalendartypes[$user->calendartype])) {
145 unset($user->calendartype);
147 } else {
148 // Unset this variable, must be an empty string, which we do not want to update the calendartype to.
149 unset($user->calendartype);
152 $user->timemodified = time();
153 $DB->update_record('user', $user);
155 if ($updatepassword) {
156 // Get full user record.
157 $updateduser = $DB->get_record('user', array('id' => $user->id));
159 // if password was set, then update its hash
160 if (isset($passwd)) {
161 $authplugin = get_auth_plugin($updateduser->auth);
162 if ($authplugin->can_change_password()) {
163 $authplugin->user_update_password($updateduser, $passwd);
168 // Trigger event.
169 $event = \core\event\user_updated::create(
170 array(
171 'objectid' => $user->id,
172 'context' => context_user::instance($user->id)
175 $event->trigger();
179 * Marks user deleted in internal user database and notifies the auth plugin.
180 * Also unenrols user from all roles and does other cleanup.
182 * @todo Decide if this transaction is really needed (look for internal TODO:)
183 * @param object $user Userobject before delete (without system magic quotes)
184 * @return boolean success
186 function user_delete_user($user) {
187 return delete_user($user);
191 * Get users by id
192 * @param array $userids id of users to retrieve
195 function user_get_users_by_id($userids) {
196 global $DB;
197 return $DB->get_records_list('user', 'id', $userids);
201 * Returns the list of default 'displayable' fields
203 * Contains database field names but also names used to generate information, such as enrolledcourses
205 * @return array of user fields
207 function user_get_default_fields() {
208 return array( 'id', 'username', 'fullname', 'firstname', 'lastname', 'email',
209 'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo', 'aim', 'msn', 'department',
210 'institution', 'interests', 'firstaccess', 'lastaccess', 'auth', 'confirmed',
211 'idnumber', 'lang', 'theme', 'timezone', 'mailformat', 'description', 'descriptionformat',
212 'city', 'url', 'country', 'profileimageurlsmall', 'profileimageurl', 'customfields',
213 'groups', 'roles', 'preferences', 'enrolledcourses'
219 * Give user record from mdl_user, build an array conntains
220 * all user details
222 * Warning: description file urls are 'webservice/pluginfile.php' is use.
223 * it can be changed with $CFG->moodlewstextformatlinkstoimagesfile
225 * @param stdClass $user user record from mdl_user
226 * @param stdClass $context context object
227 * @param stdClass $course moodle course
228 * @param array $userfields required fields
229 * @return array|null
231 function user_get_user_details($user, $course = null, array $userfields = array()) {
232 global $USER, $DB, $CFG;
233 require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
234 require_once($CFG->dirroot . "/lib/filelib.php"); // file handling on description and friends
236 $defaultfields = user_get_default_fields();
238 if (empty($userfields)) {
239 $userfields = $defaultfields;
242 foreach ($userfields as $thefield) {
243 if (!in_array($thefield, $defaultfields)) {
244 throw new moodle_exception('invaliduserfield', 'error', '', $thefield);
249 // Make sure id and fullname are included
250 if (!in_array('id', $userfields)) {
251 $userfields[] = 'id';
254 if (!in_array('fullname', $userfields)) {
255 $userfields[] = 'fullname';
258 if (!empty($course)) {
259 $context = context_course::instance($course->id);
260 $usercontext = context_user::instance($user->id);
261 $canviewdetailscap = (has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext));
262 } else {
263 $context = context_user::instance($user->id);
264 $usercontext = $context;
265 $canviewdetailscap = has_capability('moodle/user:viewdetails', $usercontext);
268 $currentuser = ($user->id == $USER->id);
269 $isadmin = is_siteadmin($USER);
271 $showuseridentityfields = get_extra_user_fields($context);
273 if (!empty($course)) {
274 $canviewhiddenuserfields = has_capability('moodle/course:viewhiddenuserfields', $context);
275 } else {
276 $canviewhiddenuserfields = has_capability('moodle/user:viewhiddendetails', $context);
278 $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
279 if (!empty($course)) {
280 $canviewuseremail = has_capability('moodle/course:useremail', $context);
281 } else {
282 $canviewuseremail = false;
284 $cannotviewdescription = !empty($CFG->profilesforenrolledusersonly) && !$currentuser && !$DB->record_exists('role_assignments', array('userid'=>$user->id));
285 if (!empty($course)) {
286 $canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
287 } else {
288 $canaccessallgroups = false;
291 if (!$currentuser && !$canviewdetailscap && !has_coursecontact_role($user->id)) {
292 // skip this user details
293 return null;
296 $userdetails = array();
297 $userdetails['id'] = $user->id;
299 if (($isadmin or $currentuser) and in_array('username', $userfields)) {
300 $userdetails['username'] = $user->username;
302 if ($isadmin or $canviewfullnames) {
303 if (in_array('firstname', $userfields)) {
304 $userdetails['firstname'] = $user->firstname;
306 if (in_array('lastname', $userfields)) {
307 $userdetails['lastname'] = $user->lastname;
310 $userdetails['fullname'] = fullname($user);
312 if (in_array('customfields', $userfields)) {
313 $fields = $DB->get_recordset_sql("SELECT f.*
314 FROM {user_info_field} f
315 JOIN {user_info_category} c
316 ON f.categoryid=c.id
317 ORDER BY c.sortorder ASC, f.sortorder ASC");
318 $userdetails['customfields'] = array();
319 foreach ($fields as $field) {
320 require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
321 $newfield = 'profile_field_'.$field->datatype;
322 $formfield = new $newfield($field->id, $user->id);
323 if ($formfield->is_visible() and !$formfield->is_empty()) {
324 $userdetails['customfields'][] =
325 array('name' => $formfield->field->name, 'value' => $formfield->data,
326 'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
329 $fields->close();
330 // unset customfields if it's empty
331 if (empty($userdetails['customfields'])) {
332 unset($userdetails['customfields']);
336 // profile image
337 if (in_array('profileimageurl', $userfields)) {
338 $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f1');
339 $userdetails['profileimageurl'] = $profileimageurl->out(false);
341 if (in_array('profileimageurlsmall', $userfields)) {
342 $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f2');
343 $userdetails['profileimageurlsmall'] = $profileimageurlsmall->out(false);
346 //hidden user field
347 if ($canviewhiddenuserfields) {
348 $hiddenfields = array();
349 // address, phone1 and phone2 not appears in hidden fields list
350 // but require viewhiddenfields capability
351 // according to user/profile.php
352 if ($user->address && in_array('address', $userfields)) {
353 $userdetails['address'] = $user->address;
355 } else {
356 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
359 if ($user->phone1 && in_array('phone1', $userfields) &&
360 (in_array('phone1', $showuseridentityfields) or $canviewhiddenuserfields)) {
361 $userdetails['phone1'] = $user->phone1;
363 if ($user->phone2 && in_array('phone2', $userfields) &&
364 (in_array('phone2', $showuseridentityfields) or $canviewhiddenuserfields)) {
365 $userdetails['phone2'] = $user->phone2;
368 if (isset($user->description) &&
369 ((!isset($hiddenfields['description']) && !$cannotviewdescription) or $isadmin)) {
370 if (in_array('description', $userfields)) {
371 // Always return the descriptionformat if description is requested.
372 list($userdetails['description'], $userdetails['descriptionformat']) =
373 external_format_text($user->description, $user->descriptionformat,
374 $usercontext->id, 'user', 'profile', null);
378 if (in_array('country', $userfields) && (!isset($hiddenfields['country']) or $isadmin) && $user->country) {
379 $userdetails['country'] = $user->country;
382 if (in_array('city', $userfields) && (!isset($hiddenfields['city']) or $isadmin) && $user->city) {
383 $userdetails['city'] = $user->city;
386 if (in_array('url', $userfields) && $user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
387 $url = $user->url;
388 if (strpos($user->url, '://') === false) {
389 $url = 'http://'. $url;
391 $user->url = clean_param($user->url, PARAM_URL);
392 $userdetails['url'] = $user->url;
395 if (in_array('icq', $userfields) && $user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
396 $userdetails['icq'] = $user->icq;
399 if (in_array('skype', $userfields) && $user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
400 $userdetails['skype'] = $user->skype;
402 if (in_array('yahoo', $userfields) && $user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
403 $userdetails['yahoo'] = $user->yahoo;
405 if (in_array('aim', $userfields) && $user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
406 $userdetails['aim'] = $user->aim;
408 if (in_array('msn', $userfields) && $user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
409 $userdetails['msn'] = $user->msn;
412 if (in_array('firstaccess', $userfields) && (!isset($hiddenfields['firstaccess']) or $isadmin)) {
413 if ($user->firstaccess) {
414 $userdetails['firstaccess'] = $user->firstaccess;
415 } else {
416 $userdetails['firstaccess'] = 0;
419 if (in_array('lastaccess', $userfields) && (!isset($hiddenfields['lastaccess']) or $isadmin)) {
420 if ($user->lastaccess) {
421 $userdetails['lastaccess'] = $user->lastaccess;
422 } else {
423 $userdetails['lastaccess'] = 0;
427 if (in_array('email', $userfields) && ($isadmin // The admin is allowed the users email
428 or $currentuser // Of course the current user is as well
429 or $canviewuseremail // this is a capability in course context, it will be false in usercontext
430 or in_array('email', $showuseridentityfields)
431 or $user->maildisplay == 1
432 or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
433 $userdetails['email'] = $user->email;
436 if (in_array('interests', $userfields) && !empty($CFG->usetags)) {
437 require_once($CFG->dirroot . '/tag/lib.php');
438 if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
439 $userdetails['interests'] = $interests;
443 //Departement/Institution/Idnumber are not displayed on any profile, however you can get them from editing profile.
444 if ($isadmin or $currentuser or in_array('idnumber', $showuseridentityfields)) {
445 if (in_array('idnumber', $userfields) && $user->idnumber) {
446 $userdetails['idnumber'] = $user->idnumber;
449 if ($isadmin or $currentuser or in_array('institution', $showuseridentityfields)) {
450 if (in_array('institution', $userfields) && $user->institution) {
451 $userdetails['institution'] = $user->institution;
454 if ($isadmin or $currentuser or in_array('department', $showuseridentityfields)) {
455 if (in_array('department', $userfields) && isset($user->department)) { //isset because it's ok to have department 0
456 $userdetails['department'] = $user->department;
460 if (in_array('roles', $userfields) && !empty($course)) {
461 // not a big secret
462 $roles = get_user_roles($context, $user->id, false);
463 $userdetails['roles'] = array();
464 foreach ($roles as $role) {
465 $userdetails['roles'][] = array(
466 'roleid' => $role->roleid,
467 'name' => $role->name,
468 'shortname' => $role->shortname,
469 'sortorder' => $role->sortorder
474 // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group
475 if (in_array('groups', $userfields) && !empty($course) && $canaccessallgroups) {
476 $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid,
477 'g.id, g.name,g.description,g.descriptionformat');
478 $userdetails['groups'] = array();
479 foreach ($usergroups as $group) {
480 list($group->description, $group->descriptionformat) =
481 external_format_text($group->description, $group->descriptionformat,
482 $context->id, 'group', 'description', $group->id);
483 $userdetails['groups'][] = array('id'=>$group->id, 'name'=>$group->name,
484 'description'=>$group->description, 'descriptionformat'=>$group->descriptionformat);
487 //list of courses where the user is enrolled
488 if (in_array('enrolledcourses', $userfields) && !isset($hiddenfields['mycourses'])) {
489 $enrolledcourses = array();
490 if ($mycourses = enrol_get_users_courses($user->id, true)) {
491 foreach ($mycourses as $mycourse) {
492 if ($mycourse->category) {
493 $coursecontext = context_course::instance($mycourse->id);
494 $enrolledcourse = array();
495 $enrolledcourse['id'] = $mycourse->id;
496 $enrolledcourse['fullname'] = format_string($mycourse->fullname, true, array('context' => $coursecontext));
497 $enrolledcourse['shortname'] = format_string($mycourse->shortname, true, array('context' => $coursecontext));
498 $enrolledcourses[] = $enrolledcourse;
501 $userdetails['enrolledcourses'] = $enrolledcourses;
505 //user preferences
506 if (in_array('preferences', $userfields) && $currentuser) {
507 $preferences = array();
508 $userpreferences = get_user_preferences();
509 foreach($userpreferences as $prefname => $prefvalue) {
510 $preferences[] = array('name' => $prefname, 'value' => $prefvalue);
512 $userdetails['preferences'] = $preferences;
515 return $userdetails;
519 * Tries to obtain user details, either recurring directly to the user's system profile
520 * or through one of the user's course enrollments (course profile).
522 * @param object $user The user.
523 * @return array if unsuccessful or the allowed user details.
525 function user_get_user_details_courses($user) {
526 global $USER;
527 $userdetails = null;
529 // Get the courses that the user is enrolled in (only active).
530 $courses = enrol_get_users_courses($user->id, true);
532 $systemprofile = false;
533 if (can_view_user_details_cap($user) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
534 $systemprofile = true;
537 // Try using system profile.
538 if ($systemprofile) {
539 $userdetails = user_get_user_details($user, null);
540 } else {
541 // Try through course profile.
542 foreach ($courses as $course) {
543 if ($can_view_user_details_cap($user, $course) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
544 $userdetails = user_get_user_details($user, $course);
549 return $userdetails;
553 * Check if $USER have the necessary capabilities to obtain user details.
555 * @param object $user
556 * @param object $course if null then only consider system profile otherwise also consider the course's profile.
557 * @return bool true if $USER can view user details.
559 function can_view_user_details_cap($user, $course = null) {
560 // Check $USER has the capability to view the user details at user context.
561 $usercontext = context_user::instance($user->id);
562 $result = has_capability('moodle/user:viewdetails', $usercontext);
563 // Otherwise can $USER see them at course context.
564 if (!$result && !empty($course)) {
565 $context = context_course::instance($course->id);
566 $result = has_capability('moodle/user:viewdetails', $context);
568 return $result;
572 * Return a list of page types
573 * @param string $pagetype current page type
574 * @param stdClass $parentcontext Block's parent context
575 * @param stdClass $currentcontext Current context of block
577 function user_page_type_list($pagetype, $parentcontext, $currentcontext) {
578 return array('user-profile'=>get_string('page-user-profile', 'pagetype'));