MDL-21572 grade: make user profile fields configurable
[moodle.git] / user / lib.php
CommitLineData
fb79269b 1<?php
2
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.
14//
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/>.
17
18/**
19 * External user API
20 *
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
25 */
26
27
28/**
29 * Creates a user
adfb459c 30 *
fb79269b 31 * @param object $user user to create
32 * @return int id of the newly created user
33 */
34function user_create_user($user) {
35 global $DB;
36
adfb459c 37 // set the timecreate field to the current time
fb79269b 38 if (!is_object($user)) {
39 $user = (object)$user;
40 }
bd0f26bd 41
45b4464c
JM
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');
48 }
49 }
50
adfb459c
JM
51 // save the password in a temp value for later
52 if (isset($user->password)) {
53
54 //check password toward the password policy
55 if (!check_password_policy($user->password, $errmsg)) {
56 throw new moodle_exception($errmsg);
57 }
58
59 $userpassword = $user->password;
60 unset($user->password);
61 }
bd0f26bd 62
fb79269b 63 $user->timecreated = time();
bd0f26bd 64 $user->timemodified = $user->timecreated;
fb79269b 65
adfb459c 66 // insert the user into the database
fb79269b 67 $newuserid = $DB->insert_record('user', $user);
68
adfb459c 69 // trigger user_created event on the full database user row
b6dcb7d9 70 $newuser = $DB->get_record('user', array('id' => $newuserid));
b6dcb7d9 71
adfb459c 72 // create USER context for this user
a0760047 73 get_context_instance(CONTEXT_USER, $newuserid);
21c968b4 74
adfb459c
JM
75 // update user password if necessary
76 if (isset($userpassword)) {
77 $authplugin = get_auth_plugin($newuser->auth);
78 $authplugin->user_update_password($newuser, $userpassword);
79 }
80
81 events_trigger('user_created', $newuser);
82
83 add_to_log(SITEID, 'user', get_string('create'), '/view.php?id='.$newuser->id,
84 fullname($newuser));
85
fb79269b 86 return $newuserid;
bd0f26bd 87
fb79269b 88}
89
90/**
91 * Update a user with a user object (will compare against the ID)
adfb459c
JM
92 *
93 * @param object $user the user to update
fb79269b 94 */
95function user_update_user($user) {
96 global $DB;
bd0f26bd 97
adfb459c 98 // set the timecreate field to the current time
bd0f26bd 99 if (!is_object($user)) {
100 $user = (object)$user;
101 }
adfb459c 102
45b4464c
JM
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');
110 }
111 }
112 }
113
adfb459c 114 // unset password here, for updating later
9e63c0ff 115 if (isset($user->password)) {
adfb459c
JM
116
117 //check password toward the password policy
118 if (!check_password_policy($user->password, $errmsg)) {
119 throw new moodle_exception($errmsg);
120 }
121
9e63c0ff
FS
122 $passwd = $user->password;
123 unset($user->password);
124 }
bd0f26bd 125
126 $user->timemodified = time();
fb79269b 127 $DB->update_record('user', $user);
b6dcb7d9 128
adfb459c 129 // trigger user_updated event on the full database user row
b6dcb7d9 130 $updateduser = $DB->get_record('user', array('id' => $user->id));
9e63c0ff 131
adfb459c
JM
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);
137 }
138 }
9e63c0ff 139
b6dcb7d9
JM
140 events_trigger('user_updated', $updateduser);
141
adfb459c
JM
142 add_to_log(SITEID, 'user', get_string('update'), '/view.php?id='.$updateduser->id,
143 fullname($updateduser));
fb79269b 144
adfb459c 145}
fb79269b 146
147/**
148 * Marks user deleted in internal user database and notifies the auth plugin.
149 * Also unenrols user from all roles and does other cleanup.
150 *
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
154 */
155function user_delete_user($user) {
45fb2cf8 156 return delete_user($user);
fb79269b 157}
158
159/**
160 * Get users by id
161 * @param array $userids id of users to retrieve
162 *
163 */
164function user_get_users_by_id($userids) {
165 global $DB;
166 return $DB->get_records_list('user', 'id', $userids);
167}
b1627a92 168
01479290
DC
169
170/**
171 *
172 * Give user record from mdl_user, build an array conntains
173 * all user details
93ce0e82
JM
174 *
175 * Warning: description file urls are 'webservice/pluginfile.php' is use.
176 * it can be changed with $CFG->moodlewstextformatlinkstoimagesfile
177 *
01479290
DC
178 * @param stdClass $user user record from mdl_user
179 * @param stdClass $context context object
180 * @param stdClass $course moodle course
ad7612f5 181 * @param array $userfields required fields
01479290
DC
182 * @return array
183 */
ad7612f5 184function user_get_user_details($user, $course = null, array $userfields = array()) {
01479290
DC
185 global $USER, $DB, $CFG;
186 require_once($CFG->dirroot . "/user/profile/lib.php"); //custom field library
187 require_once($CFG->dirroot . "/lib/filelib.php"); // file handling on description and friends
188
ad7612f5
DC
189 $defaultfields = array( 'id', 'username', 'fullname', 'firstname', 'lastname', 'email',
190 'address', 'phone1', 'phone2', 'icq', 'skype', 'yahoo', 'aim', 'msn', 'department',
191 'institution', 'interests', 'firstaccess', 'lastaccess', 'auth', 'confirmed',
192 'idnumber', 'lang', 'theme', 'timezone', 'mailformat', 'description', 'descriptionformat',
193 'city', 'url', 'country', 'profileimageurlsmall', 'profileimageurl', 'customfields',
194 'groups', 'roles', 'preferences', 'enrolledcourses'
195 );
196
197 if (empty($userfields)) {
198 $userfields = $defaultfields;
199 }
200
201 foreach ($userfields as $thefield) {
202 if (!in_array($thefield, $defaultfields)) {
203 throw new moodle_exception('invaliduserfield', 'error', '', $thefield);
204 }
205 }
206
207
208 // Make sure id and fullname are included
209 if (!in_array('id', $userfields)) {
210 $userfields[] = 'id';
211 }
212
213 if (!in_array('fullname', $userfields)) {
214 $userfields[] = 'fullname';
215 }
216
01479290
DC
217 if (!empty($course)) {
218 $context = get_context_instance(CONTEXT_COURSE, $course->id);
219 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
1e539f64 220 $canviewdetailscap = (has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext));
01479290
DC
221 } else {
222 $context = get_context_instance(CONTEXT_USER, $user->id);
223 $usercontext = $context;
1e539f64 224 $canviewdetailscap = has_capability('moodle/user:viewdetails', $usercontext);
01479290
DC
225 }
226
227 $currentuser = ($user->id == $USER->id);
228 $isadmin = is_siteadmin($USER);
229
230 if (!empty($course)) {
231 $canviewhiddenuserfields = has_capability('moodle/course:viewhiddenuserfields', $context);
232 } else {
233 $canviewhiddenuserfields = has_capability('moodle/user:viewhiddendetails', $context);
234 }
01479290
DC
235 $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
236 if (!empty($course)) {
237 $canviewuseremail = has_capability('moodle/course:useremail', $context);
238 } else {
239 $canviewuseremail = false;
240 }
241 $cannotviewdescription = !empty($CFG->profilesforenrolledusersonly) && !$currentuser && !$DB->record_exists('role_assignments', array('userid'=>$user->id));
242 if (!empty($course)) {
243 $canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
244 } else {
245 $canaccessallgroups = false;
246 }
247
248 if (!$currentuser && !$canviewdetailscap && !has_coursecontact_role($user->id)) {
249 // skip this user details
250 return null;
251 }
252
253 $userdetails = array();
254 $userdetails['id'] = $user->id;
255
ad7612f5 256 if (($isadmin or $currentuser) and in_array('username', $userfields)) {
01479290
DC
257 $userdetails['username'] = $user->username;
258 }
259 if ($isadmin or $canviewfullnames) {
ad7612f5
DC
260 if (in_array('firstname', $userfields)) {
261 $userdetails['firstname'] = $user->firstname;
262 }
263 if (in_array('lastname', $userfields)) {
264 $userdetails['lastname'] = $user->lastname;
265 }
01479290
DC
266 }
267 $userdetails['fullname'] = fullname($user);
268
ad7612f5
DC
269 if (in_array('customfields', $userfields)) {
270 $fields = $DB->get_recordset_sql("SELECT f.*
271 FROM {user_info_field} f
272 JOIN {user_info_category} c
273 ON f.categoryid=c.id
274 ORDER BY c.sortorder ASC, f.sortorder ASC");
275 $userdetails['customfields'] = array();
276 foreach ($fields as $field) {
277 require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
278 $newfield = 'profile_field_'.$field->datatype;
279 $formfield = new $newfield($field->id, $user->id);
280 if ($formfield->is_visible() and !$formfield->is_empty()) {
281 $userdetails['customfields'][] =
282 array('name' => $formfield->field->name, 'value' => $formfield->data,
283 'type' => $field->datatype, 'shortname' => $formfield->field->shortname);
284 }
285 }
286 $fields->close();
287 // unset customfields if it's empty
288 if (empty($userdetails['customfields'])) {
289 unset($userdetails['customfields']);
01479290 290 }
01479290
DC
291 }
292
293 // profile image
ad7612f5
DC
294 if (in_array('profileimageurl', $userfields)) {
295 $profileimageurl = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f1');
296 $userdetails['profileimageurl'] = $profileimageurl->out(false);
297 }
298 if (in_array('profileimageurlsmall', $userfields)) {
299 $profileimageurlsmall = moodle_url::make_pluginfile_url($usercontext->id, 'user', 'icon', NULL, '/', 'f2');
300 $userdetails['profileimageurlsmall'] = $profileimageurlsmall->out(false);
301 }
01479290
DC
302
303 //hidden user field
304 if ($canviewhiddenuserfields) {
305 $hiddenfields = array();
306 // address, phone1 and phone2 not appears in hidden fields list
307 // but require viewhiddenfields capability
308 // according to user/profile.php
ad7612f5 309 if ($user->address && in_array('address', $userfields)) {
01479290
DC
310 $userdetails['address'] = $user->address;
311 }
ad7612f5 312 if ($user->phone1 && in_array('phone1', $userfields)) {
01479290
DC
313 $userdetails['phone1'] = $user->phone1;
314 }
ad7612f5 315 if ($user->phone2 && in_array('phone2', $userfields)) {
01479290
DC
316 $userdetails['phone2'] = $user->phone2;
317 }
318 } else {
319 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
320 }
321
322 if (isset($user->description) && (!isset($hiddenfields['description']) or $isadmin)) {
323 if (!$cannotviewdescription) {
ad7612f5
DC
324
325 if (in_array('description', $userfields)) {
93ce0e82
JM
326 // Always return the descriptionformat if description is requested.
327 list($userdetails['description'], $userdetails['descriptionformat']) =
328 external_format_text($user->description, $user->descriptionformat,
329 $usercontext->id, 'user', 'profile', null);
ad7612f5 330 }
01479290
DC
331 }
332 }
333
ad7612f5 334 if (in_array('country', $userfields) && (!isset($hiddenfields['country']) or $isadmin) && $user->country) {
01479290
DC
335 $userdetails['country'] = $user->country;
336 }
337
ad7612f5 338 if (in_array('city', $userfields) && (!isset($hiddenfields['city']) or $isadmin) && $user->city) {
01479290
DC
339 $userdetails['city'] = $user->city;
340 }
341
ad7612f5 342 if (in_array('url', $userfields) && $user->url && (!isset($hiddenfields['webpage']) or $isadmin)) {
01479290
DC
343 $url = $user->url;
344 if (strpos($user->url, '://') === false) {
345 $url = 'http://'. $url;
346 }
347 $user->url = clean_param($user->url, PARAM_URL);
348 $userdetails['url'] = $user->url;
349 }
350
ad7612f5 351 if (in_array('icq', $userfields) && $user->icq && (!isset($hiddenfields['icqnumber']) or $isadmin)) {
01479290
DC
352 $userdetails['icq'] = $user->icq;
353 }
354
ad7612f5 355 if (in_array('skype', $userfields) && $user->skype && (!isset($hiddenfields['skypeid']) or $isadmin)) {
01479290
DC
356 $userdetails['skype'] = $user->skype;
357 }
ad7612f5 358 if (in_array('yahoo', $userfields) && $user->yahoo && (!isset($hiddenfields['yahooid']) or $isadmin)) {
01479290
DC
359 $userdetails['yahoo'] = $user->yahoo;
360 }
ad7612f5 361 if (in_array('aim', $userfields) && $user->aim && (!isset($hiddenfields['aimid']) or $isadmin)) {
01479290
DC
362 $userdetails['aim'] = $user->aim;
363 }
ad7612f5 364 if (in_array('msn', $userfields) && $user->msn && (!isset($hiddenfields['msnid']) or $isadmin)) {
01479290
DC
365 $userdetails['msn'] = $user->msn;
366 }
367
ad7612f5 368 if (in_array('firstaccess', $userfields) && (!isset($hiddenfields['firstaccess']) or $isadmin)) {
01479290
DC
369 if ($user->firstaccess) {
370 $userdetails['firstaccess'] = $user->firstaccess;
371 } else {
372 $userdetails['firstaccess'] = 0;
373 }
374 }
ad7612f5 375 if (in_array('lastaccess', $userfields) && (!isset($hiddenfields['lastaccess']) or $isadmin)) {
01479290
DC
376 if ($user->lastaccess) {
377 $userdetails['lastaccess'] = $user->lastaccess;
378 } else {
379 $userdetails['lastaccess'] = 0;
380 }
381 }
382
ca774c94
SH
383 if (in_array('email', $userfields) && ($isadmin // The admin is allowed the users email
384 or $currentuser // Of course the current user is as well
01479290
DC
385 or $canviewuseremail // this is a capability in course context, it will be false in usercontext
386 or $user->maildisplay == 1
ca774c94 387 or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
90e30b96 388 $userdetails['email'] = $user->email;
01479290
DC
389 }
390
ad7612f5 391 if (in_array('interests', $userfields) && !empty($CFG->usetags)) {
01479290
DC
392 require_once($CFG->dirroot . '/tag/lib.php');
393 if ($interests = tag_get_tags_csv('user', $user->id, TAG_RETURN_TEXT) ) {
394 $userdetails['interests'] = $interests;
395 }
396 }
397
398 //Departement/Institution are not displayed on any profile, however you can get them from editing profile.
399 if ($isadmin or $currentuser) {
ad7612f5 400 if (in_array('institution', $userfields) && $user->institution) {
01479290
DC
401 $userdetails['institution'] = $user->institution;
402 }
ad7612f5 403 if (in_array('department', $userfields) && isset($user->department)) { //isset because it's ok to have department 0
01479290
DC
404 $userdetails['department'] = $user->department;
405 }
406 }
407
ad7612f5 408 if (in_array('roles', $userfields) && !empty($course)) {
01479290
DC
409 // not a big secret
410 $roles = get_user_roles($context, $user->id, false);
411 $userdetails['roles'] = array();
412 foreach ($roles as $role) {
413 $userdetails['roles'][] = array(
414 'roleid' => $role->roleid,
415 'name' => $role->name,
416 'shortname' => $role->shortname,
417 'sortorder' => $role->sortorder
418 );
419 }
420 }
421
422 // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group
ad7612f5 423 if (in_array('groups', $userfields) && !empty($course) && $canaccessallgroups) {
93ce0e82
JM
424 $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid,
425 'g.id, g.name,g.description,g.descriptionformat');
01479290
DC
426 $userdetails['groups'] = array();
427 foreach ($usergroups as $group) {
93ce0e82
JM
428 list($group->description, $group->descriptionformat) =
429 external_format_text($group->description, $group->descriptionformat,
430 $context->id, 'group', 'description', $group->id);
431 $userdetails['groups'][] = array('id'=>$group->id, 'name'=>$group->name,
432 'description'=>$group->description, 'descriptionformat'=>$group->descriptionformat);
01479290
DC
433 }
434 }
435 //list of courses where the user is enrolled
ad7612f5 436 if (in_array('enrolledcourses', $userfields) && !isset($hiddenfields['mycourses'])) {
01479290
DC
437 $enrolledcourses = array();
438 if ($mycourses = enrol_get_users_courses($user->id, true)) {
439 foreach ($mycourses as $mycourse) {
440 if ($mycourse->category) {
8ebbb06a 441 $coursecontext = get_context_instance(CONTEXT_COURSE, $mycourse->id);
01479290
DC
442 $enrolledcourse = array();
443 $enrolledcourse['id'] = $mycourse->id;
91d284c1 444 $enrolledcourse['fullname'] = format_string($mycourse->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $mycourse->id)));
8ebbb06a 445 $enrolledcourse['shortname'] = format_string($mycourse->shortname, true, array('context' => $coursecontext));
01479290
DC
446 $enrolledcourses[] = $enrolledcourse;
447 }
448 }
449 $userdetails['enrolledcourses'] = $enrolledcourses;
450 }
451 }
452
453 //user preferences
ad7612f5 454 if (in_array('preferences', $userfields) && $currentuser) {
01479290
DC
455 $preferences = array();
456 $userpreferences = get_user_preferences();
457 foreach($userpreferences as $prefname => $prefvalue) {
458 $preferences[] = array('name' => $prefname, 'value' => $prefvalue);
459 }
460 $userdetails['preferences'] = $preferences;
461 }
ad7612f5 462
01479290
DC
463 return $userdetails;
464}
465
b1627a92
DC
466/**
467 * Return a list of page types
468 * @param string $pagetype current page type
469 * @param stdClass $parentcontext Block's parent context
470 * @param stdClass $currentcontext Current context of block
471 */
b38e2e28 472function user_page_type_list($pagetype, $parentcontext, $currentcontext) {
49ae1fdc 473 return array('user-profile'=>get_string('page-user-profile', 'pagetype'));
b1627a92 474}