Source for file user.php
Documentation is available at user.php
* Provides functionality for reading, managing and editing user data.
* @copyright Copyright (c) 2007-8 Sloodle (various contributors)
* @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL v3
* @contributor Peter R. Bloomfield
// This library expects that the Sloodle config file has already been included
// (along with the Moodle libraries)
/** Include the Sloodle IO library. */
require_once(SLOODLE_DIRROOT.
'/lib/io.php');
/** Include the general Sloodle functionality. */
require_once(SLOODLE_DIRROOT.
'/lib/general.php');
/** Include the Sloodle course data structure. */
require_once(SLOODLE_DIRROOT.
'/lib/course.php');
/** Include the user object data structure */
require_once(SLOODLE_DIRROOT.
'/lib/user_object.php');
* A class to represent a single user, including Moodle and Sloodle data.
* Internal only - reference to the containing {@link SloodleSession} object.
* Note: always check that it is not null before use!
* Internal only - avatar data.
* In Moodle, corresponds to a record from the 'sloodle_users' table.
* Internal only - user data. (i.e. VLE user)
* In Moodle, corresponds to a record from the 'user' table.
* @param object &$_session Reference to the containing {@link SloodleSession} object, if available.
* Gets the unique ID of the avatar.
* @return mixed Type depends on VLE. (Integer on Moodle). Returns null if there is no avatar.
* Gets the unique ID of the VLE user.
* @return mixed Type depends on VLE. (Integer on Moodle). Returns null if there is no user
if (!isset
($this->user_data->id)) return null;
* Determines whether or not an avatar is loaded.
* Determines whether or not a VLE user is loaded.
* Gets the UUID of the avatar
* Sets the UUID of the avatar
* @param string $uuid The new UUID
* Gets the name of the avatar
* Sets the name of the avatar
* @param string $avname The new avatar name
* Gets the user's username
* Gets the first name of the user
* Gets the last name of the user
* Gets the timestamp of whenever the avatar was last active
* Sets the timestamp of when the user was last active
* @param int $timestamp A UNIX timestamp, or null to use the current time
if ($timestamp ==
null) $timestamp =
time();
* Gets the user's email address.
* @return string|nullThe user's email address, or null if none is specified of if email is disabled.
// USER LINK FUNCTIONS //
* Determines whether or not the current user and avatar are linked.
* @return bool True if they are linked, or false if not.
// Make sure there is data in both caches
// Check for the link (ignore the number 0, as that is not a valid ID)
* Links the current avatar to the current user.
* <b>NOTE:</b> does not remove any other avatar links to the VLE user.
* @return bool True if successful or false otherwise.
// Make sure there is data in both caches
// Set the linked user ID and update the database record
if (update_record('sloodle_users', $this->avatar_data)) return true;
// The operation failed, so change the user ID back
* Deletes the current avatar from the database.
* @return bool True if successful, or false on failure
// Make sure we have avatar data
// Attempt to delete the record from the database
return delete_records('sloodle_users', 'id', $this->avatar_data->id);
* Loads the specified avatar from the database.
* @param mixed $id The ID of the avatar (type depends on VLE; integer for Moodle)
* @return bool True if successful, or false otherwise.
// Make sure the ID is valid
if (!is_int($id) ||
$id <=
0) return false;
$this->avatar_data =
get_record('sloodle_users', 'id', $id);
* Finds an avatar with the given UUID and/or name, and loads its data.
* The UUID is searched for first. If that is not found, then the name is used.
* @param string $uuid The UUID of the avatar, or blank to search only by name.
* @param string $avname The name of the avatar, or blank to search only by UUID.
* @return bool True if successful, or false otherwise
// Both parameters can't be empty
if (empty($uuid) &&
empty($avname)) return false;
// Attempt to search by UUID first
$this->avatar_data =
get_record('sloodle_users', 'uuid', $uuid);
// Attempt to search by name
$this->avatar_data =
get_record('sloodle_users', 'avname', $avname);
* Load the specified user from the database
* @param mixed $id The unique identifier for the VLE user. (Type depends on VLE; integer for Moodle)
* @return bool True if successful, or false on failure
// Make sure the ID is valid
if ($id <=
0) return false;
// Attempt to load the data
$this->user_data =
get_complete_user_data('id', $id);
* Uses the current avatar data to update the database.
* @return bool True if successful, or false if the update fails
// Make sure we have avatar data
return update_record('sloodle_users', $this->avatar_data);
* Adds a new avatar to the database, and link it to the specified user.
* If successful, it deletes any matching avatar details from pending users list.
* @param mixed $userid Site-wide unique ID of a user (type depends on VLE; integer for Moodle)
* @param string $uuid UUID of the avatar
* @param string $avname Name of the avatar
* @return bool True if successful, or false if not.
// Add the data to the database
// Delete any pending avatars with the same details
delete_records('sloodle_pending_avatars', 'uuid', $uuid, 'avname', $avname);
* Adds a new unlinked avatar to the database (the entry is pending linking)
* @param string $uuid UUID of the avatar
* @param string $avname Name of the avatar
* @param int $timestamp The timestamp at which to mark the update (or null to use the current timestamp). Entries expire after a certain period.
* @return object|boolReturns the database object if successul, or false if not.
if ($timestamp ==
null) $timestamp =
time();
$pending_avatar =
new stdClass();
$pending_avatar->uuid =
$uuid;
$pending_avatar->avname =
$avname;
$pending_avatar->timeupdated =
$timestamp;
// Add the data to the database
$pending_avatar->id =
insert_record('sloodle_pending_avatars', $pending_avatar);
if (!$pending_avatar->id) {
* Auto-register a new user account for the current avatar.
* NOTE: this does NOT respect ANYTHING but the most basic Moodle accounts.
* @return string|boolThe new password (plaintext) if successful, or false if not
// Make sure we have avatar data, and reset the user data
// Construct a basic username
$username =
$baseusername;
$conflict_moodle =
record_exists('user', 'username', $username);
// If that didn't work, then try a few random variants (just a number added to the end of the name)
while ($rnd_try <
$MAX_RANDOM_TRIES &&
$conflict_moodle) {
// Pick a random 3 digit number
if ($rnd_num >=
666) $rnd_num++
; // Some users may object to this number
// Construct a new username to try
$username =
$baseusername . (string)
$rnd_num;
$conflict_moodle =
record_exists('user', 'username', $username);
// Stop if we haven't found a unique name
if ($conflict_moodle) return false;
// Looks like we got an OK username
// Generate a random password
$this->user_data =
create_user_record($username, $plain_password);
// Get the complete user data again, so that we have the password this time
// Attempt to use the first and last names of the avatar
if (isset
($nameparts[1])) $this->user_data->lastname =
$nameparts[1];
else $this->user_data->lastname =
$nameparts[0];
// Prevent emails from being sent to this user
// Attempt to update the database (we don't really care if this fails, since everything else will have worked)
// Now link the avatar to this account
* Load the avatar linked to the current user.
* @return bool,string True if a link was loaded, false if there was no link, or string 'multi' if multiple avatars are linked
// Make sure we have some user data
// Fetch all avatar records which are linked to the user
$recs =
get_records('sloodle_users', 'userid', $this->user_data->id);
if (count($recs) >
1) return 'multi';
* Find the VLE user linked to the current avatar.
* @return bool True if successful, or false if no link was found
// Make sure we have some avatar data
///// LOGIN FUNCTIONS /////
* Internally 'log-in' the current user.
* In Moodle, this just stores all the user data in the global $USER variable.
* This function will not perform automatic registration.
* @return bool True if successful, or false otherwise.
// Make sure we have some user data
$USER =
get_complete_user_data('id', $this->user_data->id);
///// COURSE FUNCTIONS /////
* Gets a numeric array of {@link SloodleCourse} objects for courses the user is enrolled in.
* WARNING: this function is not very efficient, and will likely be very slow on large sites.
* @param mixed $category Unique identifier of a category to limit the query to. Ignored if null. (Type depends on VLE; integer for Moodle)
* @return array A numeric array of {@link SloodleCourse} objects
// Make sure we have user data
// If it is the guess user, then they are not enrolled at all
if (isguestuser($this->user_data->id)) return array();
// Convert the category ID as appropriate
if ($category ==
null ||
$category <
0 ||
!is_int($category)) $category =
0;
// Modified from "get_user_capability_course()" in Moodle's "lib/accesslib.php"
// Get a list of all courses on the system
$courses =
get_courses($category);
// Go through each course
foreach ($courses as $course) {
// Check if the user can view this course and is not a guest in it.
// (Note: the site course is always available to all users.)
$course_context =
get_context_instance(CONTEXT_COURSE, $course->id);
if ($course->id ==
SITEID ||
(has_capability('moodle/course:view', $course_context, $this->user_data->id) &&
!has_capability('moodle/legacy:guest', $course_context, $this->user_data->id, false))) {
* Gets a numeric array of {@link SloodleCourse} objects for courses the user is Sloodle staff.
* This relates to the "mod/sloodle:staff" capability.
* WARNING: this function is not very efficient, and will likely be very slow on large sites.
* @param mixed $category Unique identifier of a category to limit the query to. Ignored if null. (Type depends on VLE; integer for Moodle)
* @return array A numeric array of {@link SloodleCourse} objects
// Make sure we have user data
// Convert the category ID as appropriate
if ($category ==
null ||
$category <
0 ||
!is_int($category)) $category =
0;
// Modified from "get_user_capability_course()" in Moodle's "lib/accesslib.php"
// Get a list of all courses on the system
$courses =
get_courses($category);
// Go through each course
foreach ($courses as $course) {
// Check if the user can teach using Sloodle on this course
if (has_capability('mod/sloodle:staff', get_context_instance(CONTEXT_COURSE, $course->id), $this->user_data->id)) {
* Is the current user enrolled in the specified course?
* NOTE: a side effect of this is that it logs-in the user
* @param mixed $course Unique identifier of the course -- type depends on VLE (integer for Moodle)
* @param bool True if the user is enrolled, or false if not.
* @todo Update to match parameter format and handling of {@link enrol()} function.
// Attempt to log-in the user
if (!$this->login()) return false;
// NOTE: this stuff was lifted from the Moodle 1.8 "course/enrol.php" script
// Create a context for this course
if (!$context =
get_context_instance(CONTEXT_COURSE, $courseid)) return false;
// Ensure we have up-to-date capabilities for the current user
// Check if the user can view the course, and does not simply have guest access to it
return ($courseid ==
SITEID ||
(has_capability('moodle/course:view', $context) &&
!has_capability('moodle/legacy:guest', $context, NULL, false)));
* Is the current user Sloodle staff in the specified course?
* NOTE: a side effect of this is that it logs-in the user
* @param mixed $course Unique identifier of the course -- type depends on VLE (integer for Moodle)
* @param bool True if the user is staff, or false if not.
* @todo Update to match parameter format and handling of {@link enrol()} function.
// Attempt to log-in the user
if (!$this->login()) return false;
// NOTE: this stuff was lifted from the Moodle 1.8 "course/enrol.php" script
// Create a context for this course
if (!$context =
get_context_instance(CONTEXT_COURSE, $courseid)) return false;
// Ensure we have up-to-date capabilities for the current user
// Check if the user can view the course, does not simply have guest access to it, *and* is staff
return (has_capability('moodle/course:view', $context) &&
!has_capability('moodle/legacy:guest', $context, NULL, false) &&
has_capability('mod/sloodle:staff', $context));
* Enrols the current user in the specified course
* NOTE: a side effect of this is that it logs-in the user
* @param object $sloodle_course A {@link SloodleCourse} object setup for the necessary course. If null, then the {@link $_session} member is queried instead.
* @param bool True if successful (or the user was already enrolled), or false otherwise
function enrol($sloodle_course =
null)
// Attempt to log-in the user
if (!$this->login()) return false;
// Was course data provided?
if (empty($sloodle_course)) {
// No - attempt to get some from the Sloodle session
if (empty($this->_session)) return false;
if (empty($this->_session->course)) return false;
$sloodle_course =
$this->_session->course;
// NOTE: much of this stuff was lifted from the Moodle 1.8 "course/enrol.php" script
// Fetch the Moodle course data, and a course context
$course =
$sloodle_course->get_course_object();
if (!$context =
get_context_instance(CONTEXT_COURSE, $course->id)) return false;
// Ensure we have up-to-date capabilities for the current user
// Check if the user can view the course, and does not simply have guest access to it
// (No point trying to enrol somebody if they are already enrolled!)
if (has_capability('moodle/course:view', $context) &&
!has_capability('moodle/legacy:guest', $context, NULL, false)) return true;
// Make sure auto-registration is enabled for this site/course, and that the controller (if applicable) is enabled
if (!$sloodle_course->check_autoreg()) return false;
// Can't enrol users on meta courses or the site course
if ($course->metacourse ||
$course->id ==
SITEID) return false;
// Is there an enrolment period in effect?
if ($course->enrolperiod) {
if ($roles =
get_user_roles($context, $USER->id)) {
foreach ($roles as $role) {
if ($role->timestart &&
($role->timestart >=
time())) {
// Make sure the course is enrollable
if (!$course->enrollable ||
($course->enrollable ==
2 &&
$course->enrolstartdate >
0 &&
$course->enrolstartdate >
time()) ||
($course->enrollable ==
2 &&
$course->enrolenddate >
0 &&
$course->enrolenddate <=
time())
// Finally, after all that, enrol the user
if (!enrol_into_course($course, $USER, 'manual')) return false;
// Log the auto-enrolment
add_to_log($course->id, 'sloodle', 'update', '', 'auto-enrolment');
* Resets the user's password
* @param bool $require If true, then the script will be terminated if the operation fails
* @return string|boolThe new password if successful, or false otherwise (if $require was false).
// Check that the user is loaded
$this->_session->response->quick_output(-
301, 'USER_AUTH', 'User data not loaded', false);
// If the user has an email address on file, then we can't reset the password
$this->_session->response->quick_output(-
341, 'USER_AUTH', 'User has email address in database. Cannot use Sloodle password reset.', false);
// Generate a new random password
// Update the user's password data
if (!update_internal_user_password($this->user_data, $password)) {
$this->_session->response->quick_output(-
103, 'SYSTEM', 'Failed to update user password', false);
* If the system is waiting to send a password notification to this user, then remove it
// Check that the user is loaded
// Delete the database entries
delete_records('sloodle_login_notifications', 'username', $this->user_data->username);
///// USER-CENTRIC OBJECTS /////
* Authorises the given object for the current avatar.
* Note: the object must already exist in the database.
* @param int $authid The ID of the authorisation entry
* @return bool True if successful, or false otherwise
// Make sure an avatar is loaded
// Does the object already exist in the database?
$auth =
get_record('sloodle_user_object', 'id', $authid, 'avuuid', $this->get_avatar_uuid());
if (!$auth) return false;
// Update the existing record
$auth->timeupdated =
time();
return update_record('sloodle_user_object', $auth);
* Adds or udpates the given user object as unauthorised.
* (This function can be called statically).
* @param string $avuuid UUID of the avatar the object will be authorised for
* @param string $objuuid UUID of the object
* @param string $objname Name of the object
* @param string $password Password to store for the object
* @return int|boolInteger ID of the authorisation entry, or false otherwise
// Make sure our other parameters are valid
if (empty($objuuid) ||
empty($password)) return false;
// Does the object already exist in the database?
$auth =
get_record('sloodle_user_object', 'objuuid', $objuuid);
// No - insert a new record
$auth->objuuid =
$objuuid;
$auth->objname =
$objname;
$auth->password =
$password;
$auth->timeupdated =
time();
$success =
insert_record('sloodle_user_object', $auth);
// Yes - update the existing record
$auth->objuuid =
$objuuid;
$auth->objname =
$objname;
$auth->password =
$password;
$auth->timeupdated =
time();
if (update_record('sloodle_user_object', $auth)) $success =
$auth->id;
* Gets a list of all user-centric objects authorised for the current avatar.
* @return array A numeric array of {@link SloodleUserObject} objects
// Make sure an avatar is loaded
// Get all objects authorised for this avatar's UUID
$recs =
get_records('sloodle_user_object', 'avuuid', $this->get_avatar_uuid());
if (!$recs) return array();
// Construct an array of SloodleUserObject's
$obj->avuuid =
$r->avuuid;
$obj->objuuid =
$r->objuuid;
$obj->objname =
$r->objname;
$obj->password =
$r->password;
$obj->authorized = (bool)
$r->authorised; // Note different spelling... oops! -PB
$obj->timeupdated =
$r->timeupdated;
* Deletes a user-centric object by UUID.
* Note: the object must have been authorised for the current avatar.
* @param string $uuid The UUID of the object to delete
delete_records('sloodle_user_object', 'avuuid', $this->get_avatar_uuid(), 'objuuid', $uuid);
Documentation generated on Fri, 17 Jul 2009 11:02:37 +0100 by phpDocumentor 1.4.0