MDL-38243 mod_assessment: make assessment forms non-collapsible
[moodle.git] / user / lib.php
blob4b9d4675c2a032a2f349eadd4099ba41baffcb83
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 object $user user to create
32 * @return int id of the newly created user
34 function user_create_user($user) {
35 global $DB;
37 // set the timecreate field to the current time
38 if (!is_object($user)) {
39 $user = (object)$user;
42 //check username
43 if ($user->username !== textlib::strtolower($user->username)) {
44 throw new moodle_exception('usernamelowercase');
45 } else {
46 if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
47 throw new moodle_exception('invalidusername');
51 // save the password in a temp value for later
52 if (isset($user->password)) {
54 //check password toward the password policy
55 if (!check_password_policy($user->password, $errmsg)) {
56 throw new moodle_exception($errmsg);
59 $userpassword = $user->password;
60 unset($user->password);
63 $user->timecreated = time();
64 $user->timemodified = $user->timecreated;
66 // insert the user into the database
67 $newuserid = $DB->insert_record('user', $user);
69 // trigger user_created event on the full database user row
70 $newuser = $DB->get_record('user', array('id' => $newuserid));
72 // create USER context for this user
73 context_user::instance($newuserid);
75 // update user password if necessary
76 if (isset($userpassword)) {
77 $authplugin = get_auth_plugin($newuser->auth);
78 $authplugin->user_update_password($newuser, $userpassword);
81 events_trigger('user_created', $newuser);
83 add_to_log(SITEID, 'user', get_string('create'), '/view.php?id='.$newuser->id,
84 fullname($newuser));
86 return $newuserid;
90 /**
91 * Update a user with a user object (will compare against the ID)
93 * @param object $user the user to update
95 function user_update_user($user) {
96 global $DB;
98 // set the timecreate field to the current time
99 if (!is_object($user)) {
100 $user = (object)$user;
103 //check username
104 if (isset($user->username)) {
105 if ($user->username !== textlib::strtolower($user->username)) {
106 throw new moodle_exception('usernamelowercase');
107 } else {
108 if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
109 throw new moodle_exception('invalidusername');
114 // unset password here, for updating later
115 if (isset($user->password)) {
117 //check password toward the password policy
118 if (!check_password_policy($user->password, $errmsg)) {
119 throw new moodle_exception($errmsg);
122 $passwd = $user->password;
123 unset($user->password);
126 $user->timemodified = time();
127 $DB->update_record('user', $user);
129 // trigger user_updated event on the full database user row
130 $updateduser = $DB->get_record('user', array('id' => $user->id));
132 // if password was set, then update its hash
133 if (isset($passwd)) {
134 $authplugin = get_auth_plugin($updateduser->auth);
135 if ($authplugin->can_change_password()) {
136 $authplugin->user_update_password($updateduser, $passwd);
140 events_trigger('user_updated', $updateduser);
142 add_to_log(SITEID, 'user', get_string('update'), '/view.php?id='.$updateduser->id,
143 fullname($updateduser));
148 * Marks user deleted in internal user database and notifies the auth plugin.
149 * Also unenrols user from all roles and does other cleanup.
151 * @todo Decide if this transaction is really needed (look for internal TODO:)
152 * @param object $user Userobject before delete (without system magic quotes)
153 * @return boolean success
155 function user_delete_user($user) {
156 return delete_user($user);
160 * Get users by id
161 * @param array $userids id of users to retrieve
164 function user_get_users_by_id($userids) {
165 global $DB;
166 return $DB->get_records_list('user', 'id', $userids);
170 * Returns the list of default 'displayable' fields
172 * Contains database field names but also names used to generate information, such as enrolledcourses
174 * @return array of user fields
176 function user_get_default_fields() {
177 return array( 'id', 'username', 'fullname', 'firstname', 'lastname', 'email',
178 'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo', 'aim', 'msn', 'department',
179 'institution', 'interests', 'firstaccess', 'lastaccess', 'auth', 'confirmed',
180 'idnumber', 'lang', 'theme', 'timezone', 'mailformat', 'description', 'descriptionformat',
181 'city', 'url', 'country', 'profileimageurlsmall', 'profileimageurl', 'customfields',
182 'groups', 'roles', 'preferences', 'enrolledcourses'
188 * Give user record from mdl_user, build an array conntains
189 * all user details
191 * Warning: description file urls are 'webservice/pluginfile.php' is use.
192 * it can be changed with $CFG->moodlewstextformatlinkstoimagesfile
194 * @param stdClass $user user record from mdl_user
195 * @param stdClass $context context object
196 * @param stdClass $course moodle course
197 * @param array $userfields required fields
198 * @return array|null
200 function user_get_user_details($user, $course = null, array $userfields = array()) {
201 global $USER, $DB, $CFG;
202 require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
203 require_once($CFG->dirroot . "/lib/filelib.php"); // file handling on description and friends
205 $defaultfields = user_get_default_fields();
207 if (empty($userfields)) {
208 $userfields = $defaultfields;
211 foreach ($userfields as $thefield) {
212 if (!in_array($thefield, $defaultfields)) {
213 throw new moodle_exception('invaliduserfield', 'error', '', $thefield);
218 // Make sure id and fullname are included
219 if (!in_array('id', $userfields)) {
220 $userfields[] = 'id';
223 if (!in_array('fullname', $userfields)) {
224 $userfields[] = 'fullname';
227 if (!empty($course)) {
228 $context = context_course::instance($course->id);
229 $usercontext = context_user::instance($user->id);
230 $canviewdetailscap = (has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext));
231 } else {
232 $context = context_user::instance($user->id);
233 $usercontext = $context;
234 $canviewdetailscap = has_capability('moodle/user:viewdetails', $usercontext);
237 $currentuser = ($user->id == $USER->id);
238 $isadmin = is_siteadmin($USER);
240 $showuseridentityfields = get_extra_user_fields($context);
242 if (!empty($course)) {
243 $canviewhiddenuserfields = has_capability('moodle/course:viewhiddenuserfields', $context);
244 } else {
245 $canviewhiddenuserfields = has_capability('moodle/user:viewhiddendetails', $context);
247 $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
248 if (!empty($course)) {
249 $canviewuseremail = has_capability('moodle/course:useremail', $context);
250 } else {
251 $canviewuseremail = false;
253 $cannotviewdescription = !empty($CFG->profilesforenrolledusersonly) && !$currentuser && !$DB->record_exists('role_assignments', array('userid'=>$user->id));
254 if (!empty($course)) {
255 $canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
256 } else {
257 $canaccessallgroups = false;
260 if (!$currentuser && !$canviewdetailscap && !has_coursecontact_role($user->id)) {
261 // skip this user details
262 return null;
265 $userdetails = array();
266 $userdetails['id'] = $user->id;
268 if (($isadmin or $currentuser) and in_array('username', $userfields)) {
269 $userdetails['username'] = $user->username;
271 if ($isadmin or $canviewfullnames) {
272 if (in_array('firstname', $userfields)) {
273 $userdetails['firstname'] = $user->firstname;
275 if (in_array('lastname', $userfields)) {
276 $userdetails['lastname'] = $user->lastname;
279 $userdetails['fullname'] = fullname($user);
281 if (in_array('customfields', $userfields)) {
282 $fields = $DB->get_recordset_sql("SELECT f.*
283 FROM {user_info_field} f
284 JOIN {user_info_category} c
285 ON f.categoryid=c.id
286 ORDER BY c.sortorder ASC, f.sortorder ASC");
287 $userdetails['customfields'] = array();
288 foreach ($fields as $field) {
289 require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
290 $newfield = 'profile_field_'.$field->datatype;
291 $formfield = new $newfield($field->id, $user->id);
292 if ($formfield->is_visible() and !$formfield->is_empty()) {
293 $userdetails['customfields'][] =
294 array('name' => $formfield->field->name, 'value' => $formfield->data,
295 'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
298 $fields->close();
299 // unset customfields if it's empty
300 if (empty($userdetails['customfields'])) {
301 unset($userdetails['customfields']);
305 // profile image
306 if (in_array('profileimageurl', $userfields)) {
307 $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f1');
308 $userdetails['profileimageurl'] = $profileimageurl->out(false);
310 if (in_array('profileimageurlsmall', $userfields)) {
311 $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f2');
312 $userdetails['profileimageurlsmall'] = $profileimageurlsmall->out(false);
315 //hidden user field
316 if ($canviewhiddenuserfields) {
317 $hiddenfields = array();
318 // address, phone1 and phone2 not appears in hidden fields list
319 // but require viewhiddenfields capability
320 // according to user/profile.php
321 if ($user->address && in_array('address', $userfields)) {
322 $userdetails['address'] = $user->address;
324 } else {
325 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
328 if ($user->phone1 && in_array('phone1', $userfields) &&
329 (isset($showuseridentityfields['phone1']) or $canviewhiddenuserfields)) {
330 $userdetails['phone1'] = $user->phone1;
332 if ($user->phone2 && in_array('phone2', $userfields) &&
333 (isset($showuseridentityfields['phone2']) or $canviewhiddenuserfields)) {
334 $userdetails['phone2'] = $user->phone2;
337 if (isset($user->description) &&
338 ((!isset($hiddenfields['description']) && !$cannotviewdescription) or $isadmin)) {
339 if (in_array('description', $userfields)) {
340 // Always return the descriptionformat if description is requested.
341 list($userdetails['description'], $userdetails['descriptionformat']) =
342 external_format_text($user->description, $user->descriptionformat,
343 $usercontext->id, 'user', 'profile', null);
347 if (in_array('country', $userfields) && (!isset($hiddenfields['country']) or $isadmin) && $user->country) {
348 $userdetails['country'] = $user->country;
351 if (in_array('city', $userfields) && (!isset($hiddenfields['city']) or $isadmin) && $user->city) {
352 $userdetails['city'] = $user->city;
355 if (in_array('url', $userfields) && $user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
356 $url = $user->url;
357 if (strpos($user->url, '://') === false) {
358 $url = 'http://'. $url;
360 $user->url = clean_param($user->url, PARAM_URL);
361 $userdetails['url'] = $user->url;
364 if (in_array('icq', $userfields) && $user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
365 $userdetails['icq'] = $user->icq;
368 if (in_array('skype', $userfields) && $user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
369 $userdetails['skype'] = $user->skype;
371 if (in_array('yahoo', $userfields) && $user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
372 $userdetails['yahoo'] = $user->yahoo;
374 if (in_array('aim', $userfields) && $user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
375 $userdetails['aim'] = $user->aim;
377 if (in_array('msn', $userfields) && $user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
378 $userdetails['msn'] = $user->msn;
381 if (in_array('firstaccess', $userfields) && (!isset($hiddenfields['firstaccess']) or $isadmin)) {
382 if ($user->firstaccess) {
383 $userdetails['firstaccess'] = $user->firstaccess;
384 } else {
385 $userdetails['firstaccess'] = 0;
388 if (in_array('lastaccess', $userfields) && (!isset($hiddenfields['lastaccess']) or $isadmin)) {
389 if ($user->lastaccess) {
390 $userdetails['lastaccess'] = $user->lastaccess;
391 } else {
392 $userdetails['lastaccess'] = 0;
396 if (in_array('email', $userfields) && ($isadmin // The admin is allowed the users email
397 or $currentuser // Of course the current user is as well
398 or $canviewuseremail // this is a capability in course context, it will be false in usercontext
399 or isset($showuseridentityfields['email'])
400 or $user->maildisplay == 1
401 or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
402 $userdetails['email'] = $user->email;
405 if (in_array('interests', $userfields) && !empty($CFG->usetags)) {
406 require_once($CFG->dirroot . '/tag/lib.php');
407 if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
408 $userdetails['interests'] = $interests;
412 //Departement/Institution/Idnumber are not displayed on any profile, however you can get them from editing profile.
413 if ($isadmin or $currentuser or isset($showuseridentityfields['idnumber'])) {
414 if (in_array('idnumber', $userfields) && $user->idnumber) {
415 $userdetails['idnumber'] = $user->idnumber;
418 if ($isadmin or $currentuser or isset($showuseridentityfields['institution'])) {
419 if (in_array('institution', $userfields) && $user->institution) {
420 $userdetails['institution'] = $user->institution;
423 if ($isadmin or $currentuser or isset($showuseridentityfields['department'])) {
424 if (in_array('department', $userfields) && isset($user->department)) { //isset because it's ok to have department 0
425 $userdetails['department'] = $user->department;
429 if (in_array('roles', $userfields) && !empty($course)) {
430 // not a big secret
431 $roles = get_user_roles($context, $user->id, false);
432 $userdetails['roles'] = array();
433 foreach ($roles as $role) {
434 $userdetails['roles'][] = array(
435 'roleid' => $role->roleid,
436 'name' => $role->name,
437 'shortname' => $role->shortname,
438 'sortorder' => $role->sortorder
443 // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group
444 if (in_array('groups', $userfields) && !empty($course) && $canaccessallgroups) {
445 $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid,
446 'g.id, g.name,g.description,g.descriptionformat');
447 $userdetails['groups'] = array();
448 foreach ($usergroups as $group) {
449 list($group->description, $group->descriptionformat) =
450 external_format_text($group->description, $group->descriptionformat,
451 $context->id, 'group', 'description', $group->id);
452 $userdetails['groups'][] = array('id'=>$group->id, 'name'=>$group->name,
453 'description'=>$group->description, 'descriptionformat'=>$group->descriptionformat);
456 //list of courses where the user is enrolled
457 if (in_array('enrolledcourses', $userfields) && !isset($hiddenfields['mycourses'])) {
458 $enrolledcourses = array();
459 if ($mycourses = enrol_get_users_courses($user->id, true)) {
460 foreach ($mycourses as $mycourse) {
461 if ($mycourse->category) {
462 $coursecontext = context_course::instance($mycourse->id);
463 $enrolledcourse = array();
464 $enrolledcourse['id'] = $mycourse->id;
465 $enrolledcourse['fullname'] = format_string($mycourse->fullname, true, array('context' => $coursecontext));
466 $enrolledcourse['shortname'] = format_string($mycourse->shortname, true, array('context' => $coursecontext));
467 $enrolledcourses[] = $enrolledcourse;
470 $userdetails['enrolledcourses'] = $enrolledcourses;
474 //user preferences
475 if (in_array('preferences', $userfields) && $currentuser) {
476 $preferences = array();
477 $userpreferences = get_user_preferences();
478 foreach($userpreferences as $prefname => $prefvalue) {
479 $preferences[] = array('name' => $prefname, 'value' => $prefvalue);
481 $userdetails['preferences'] = $preferences;
484 return $userdetails;
488 * Tries to obtain user details, either recurring directly to the user's system profile
489 * or through one of the user's course enrollments (course profile).
491 * @param object $user The user.
492 * @return array if unsuccessful or the allowed user details.
494 function user_get_user_details_courses($user) {
495 global $USER;
496 $userdetails = null;
498 // Get the courses that the user is enrolled in (only active).
499 $courses = enrol_get_users_courses($user->id, true);
501 $systemprofile = false;
502 if (can_view_user_details_cap($user) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
503 $systemprofile = true;
506 // Try using system profile.
507 if ($systemprofile) {
508 $userdetails = user_get_user_details($user, null);
509 } else {
510 // Try through course profile.
511 foreach ($courses as $course) {
512 if ($can_view_user_details_cap($user, $course) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
513 $userdetails = user_get_user_details($user, $course);
518 return $userdetails;
522 * Check if $USER have the necessary capabilities to obtain user details.
524 * @param object $user
525 * @param object $course if null then only consider system profile otherwise also consider the course's profile.
526 * @return bool true if $USER can view user details.
528 function can_view_user_details_cap($user, $course = null) {
529 // Check $USER has the capability to view the user details at user context.
530 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
531 $result = has_capability('moodle/user:viewdetails', $usercontext);
532 // Otherwise can $USER see them at course context.
533 if (!$result && !empty($course)) {
534 $context = get_context_instance(CONTEXT_COURSE, $course->id);
535 $result = has_capability('moodle/user:viewdetails', $context);
537 return $result;
541 * Return a list of page types
542 * @param string $pagetype current page type
543 * @param stdClass $parentcontext Block's parent context
544 * @param stdClass $currentcontext Current context of block
546 function user_page_type_list($pagetype, $parentcontext, $currentcontext) {
547 return array('user-profile'=>get_string('page-user-profile', 'pagetype'));