user.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. <?php
  2. /**
  3. * Sloodle user library.
  4. *
  5. * Provides functionality for reading, managing and editing user data.
  6. *
  7. * @package sloodle
  8. * @copyright Copyright (c) 2007-8 Sloodle (various contributors)
  9. * @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL v3
  10. * @since Sloodle 0.2
  11. *
  12. * @contributor Peter R. Bloomfield
  13. *
  14. */
  15. // This library expects that the Sloodle config file has already been included
  16. // (along with the Moodle libraries)
  17. /** Include the Sloodle IO library. */
  18. require_once(SLOODLE_DIRROOT.'/lib/io.php');
  19. /** Include the general Sloodle functionality. */
  20. require_once(SLOODLE_DIRROOT.'/lib/general.php');
  21. /** Include the Sloodle course data structure. */
  22. require_once(SLOODLE_DIRROOT.'/lib/course.php');
  23. /** Include the user object data structure */
  24. require_once(SLOODLE_DIRROOT.'/lib/user_object.php');
  25. /**
  26. * A class to represent a single user, including Moodle and Sloodle data.
  27. * @package sloodle
  28. */
  29. class SloodleUser
  30. {
  31. // DATA //
  32. /**
  33. * Internal only - reference to the containing {@link SloodleSession} object.
  34. * Note: always check that it is not null before use!
  35. * @var object
  36. * @access protected
  37. */
  38. var $_session = null;
  39. /**
  40. * Internal only - avatar data.
  41. * In Moodle, corresponds to a record from the 'sloodle_users' table.
  42. * @var object
  43. * @access private
  44. */
  45. var $avatar_data = null;
  46. /**
  47. * Internal only - user data. (i.e. VLE user)
  48. * In Moodle, corresponds to a record from the 'user' table.
  49. * @var obejct
  50. * @access private
  51. */
  52. var $user_data = null;
  53. // CONSTRUCTOR //
  54. /**
  55. * Class constructor.
  56. * @param object &$_session Reference to the containing {@link SloodleSession} object, if available.
  57. * @access public
  58. */
  59. function SloodleUser(&$_session = null)
  60. {
  61. if (!is_null($_session)) $this->_session = &$_session;
  62. }
  63. // ACCESSORS //
  64. /**
  65. * Gets the unique ID of the avatar.
  66. * @return mixed Type depends on VLE. (Integer on Moodle). Returns null if there is no avatar.
  67. * @access public
  68. */
  69. function get_avatar_id()
  70. {
  71. if (!isset($this->avatar_data->id)) return null;
  72. return $this->avatar_data->id;
  73. }
  74. /**
  75. * Gets the unique ID of the VLE user.
  76. * @return mixed Type depends on VLE. (Integer on Moodle). Returns null if there is no user
  77. * @access public
  78. */
  79. function get_user_id()
  80. {
  81. if (!isset($this->user_data->id)) return null;
  82. return $this->user_data->id;
  83. }
  84. /**
  85. * Determines whether or not an avatar is loaded.
  86. * @return bool
  87. */
  88. function is_avatar_loaded()
  89. {
  90. return isset($this->avatar_data);
  91. }
  92. /**
  93. * Determines whether or not a VLE user is loaded.
  94. * @return bool
  95. */
  96. function is_user_loaded()
  97. {
  98. return isset($this->user_data);
  99. }
  100. /**
  101. * Gets the UUID of the avatar
  102. * @return string
  103. */
  104. function get_avatar_uuid()
  105. {
  106. return $this->avatar_data->uuid;
  107. }
  108. /**
  109. * Sets the UUID of the avatar
  110. * @param string $uuid The new UUID
  111. * @return void
  112. */
  113. function set_avatar_uuid($uuid)
  114. {
  115. $this->avatar_data->uuid = $uuid;
  116. }
  117. /**
  118. * Gets the name of the avatar
  119. * @return string
  120. */
  121. function get_avatar_name()
  122. {
  123. return $this->avatar_data->avname;
  124. }
  125. /**
  126. * Sets the name of the avatar
  127. * @param string $avname The new avatar name
  128. * @return void
  129. */
  130. function set_avatar_name($avname)
  131. {
  132. $this->avatar_data->avname = $avname;
  133. }
  134. /**
  135. * Gets the user's username
  136. * @return string
  137. */
  138. function get_username()
  139. {
  140. return $this->user_data->username;
  141. }
  142. /**
  143. * Gets the first name of the user
  144. * @return string
  145. */
  146. function get_user_firstname()
  147. {
  148. return $this->user_data->firstname;
  149. }
  150. /**
  151. * Gets the last name of the user
  152. * @return string
  153. */
  154. function get_user_lastname()
  155. {
  156. return $this->user_data->lastname;
  157. }
  158. /**
  159. * Gets the timestamp of whenever the avatar was last active
  160. * @return int
  161. */
  162. function get_avatar_last_active()
  163. {
  164. return (int)$this->avatar_data->lastactive;
  165. }
  166. /**
  167. * Sets the timestamp of when the user was last active
  168. * @param int $timestamp A UNIX timestamp, or null to use the current time
  169. * @return void
  170. */
  171. function set_avatar_last_active($timestamp = null)
  172. {
  173. if ($timestamp == null) $timestamp = time();
  174. $this->avatar_data->lastactive = $timestamp;
  175. }
  176. /**
  177. * Gets the user's email address.
  178. * @return string|null The user's email address, or null if none is specified of if email is disabled.
  179. */
  180. function get_user_email()
  181. {
  182. if (isset($this->user_data->email) && !empty($this->user_data->emailstop))
  183. return $this->user_data->email;
  184. return null;
  185. }
  186. // USER LINK FUNCTIONS //
  187. /**
  188. * Determines whether or not the current user and avatar are linked.
  189. * @return bool True if they are linked, or false if not.
  190. */
  191. function is_avatar_linked()
  192. {
  193. // Make sure there is data in both caches
  194. if (empty($this->avatar_data) || empty($this->user_data)) return false;
  195. // Check for the link (ignore the number 0, as that is not a valid ID)
  196. if ($this->avatar_data->userid != 0 && $this->avatar_data->userid == $this->user_data->id) return true;
  197. return false;
  198. }
  199. /**
  200. * Links the current avatar to the current user.
  201. * <b>NOTE:</b> does not remove any other avatar links to the VLE user.
  202. * @return bool True if successful or false otherwise.
  203. * @access public
  204. */
  205. function link_avatar()
  206. {
  207. // Make sure there is data in both caches
  208. if (empty($this->avatar_data) || empty($this->user_data)) return false;
  209. // Set the linked user ID and update the database record
  210. $olduserid = $this->avatar_data->userid;
  211. $this->avatar_data->userid = $this->user_data->id;
  212. if (sloodle_update_record('sloodle_users', $this->avatar_data)) return true;
  213. // The operation failed, so change the user ID back
  214. $this->avatar_data->userid = $olduserid;
  215. return false;
  216. }
  217. // DATABASE FUNCTIONS //
  218. /**
  219. * Deletes the current avatar from the database.
  220. * @return bool True if successful, or false on failure
  221. * @access public
  222. */
  223. function delete_avatar()
  224. {
  225. // Make sure we have avatar data
  226. if (empty($this->avatar_data)) return false;
  227. // Attempt to delete the record from the database
  228. return sloodle_delete_records('sloodle_users', 'id', $this->avatar_data->id);
  229. }
  230. /**
  231. * Loads the specified avatar from the database.
  232. * @param mixed $id The Moodle User ID of the avatar
  233. * @return bool True if successful, or false otherwise.
  234. * @access public
  235. */
  236. function load_avatar_by_user_id($id)
  237. {
  238. // Make sure the ID is valid
  239. $id = intval($id);
  240. if (!$id) {
  241. return false;
  242. }
  243. // Fetch the avatar data
  244. $this->avatar_data = sloodle_get_record('sloodle_users', 'userid', $id);
  245. if (!$this->avatar_data) {
  246. $this->avatar_data = null;
  247. return false;
  248. }
  249. return true;
  250. }
  251. /**
  252. * Finds an avatar with the given UUID and/or name, and loads its data.
  253. * The UUID is searched for first. If that is not found, then the name is used.
  254. * @param string $uuid The UUID of the avatar, or blank to search only by name.
  255. * @param string $avname The name of the avatar, or blank to search only by UUID.
  256. * @return bool True if successful, or false otherwise
  257. * @access public
  258. */
  259. function load_avatar($uuid, $avname)
  260. {
  261. // Both parameters can't be empty
  262. if (empty($uuid) && empty($avname)) return false;
  263. // Attempt to search by UUID first
  264. if (!empty($uuid)) {
  265. $this->avatar_data = sloodle_get_record('sloodle_users', 'uuid', $uuid);
  266. if ($this->avatar_data) return true;
  267. }
  268. // Attempt to search by name
  269. if (!empty($avname)) {
  270. $this->avatar_data = sloodle_get_record('sloodle_users', 'avname', $avname);
  271. if ($this->avatar_data) return true;
  272. }
  273. // The search failed
  274. $this->avatar_data = null;
  275. return false;
  276. }
  277. /**
  278. * Load the specified user from the database
  279. * @param mixed $id The unique identifier for the VLE user. (Type depends on VLE; integer for Moodle)
  280. * @return bool True if successful, or false on failure
  281. * @access public
  282. */
  283. function load_user($id)
  284. {
  285. // Make sure the ID is valid
  286. $id = (int)$id;
  287. if ($id <= 0) return false;
  288. // Attempt to load the data
  289. $this->user_data = get_complete_user_data('id', $id);
  290. if (!$this->user_data) {
  291. $this->user_data = null;
  292. return false;
  293. }
  294. return true;
  295. }
  296. /**
  297. * Uses the current avatar data to update the database.
  298. * @return bool True if successful, or false if the update fails
  299. * @access public
  300. */
  301. function write_avatar()
  302. {
  303. // Make sure we have avatar data
  304. if (empty($this->avatar_data) || $this->avatar_data->id <= 0) return false;
  305. // Make the update
  306. return sloodle_update_record('sloodle_users', $this->avatar_data);
  307. }
  308. /**
  309. * Adds a new avatar to the database, and link it to the specified user.
  310. * If successful, it deletes any matching avatar details from pending users list.
  311. * @param mixed $userid Site-wide unique ID of a user (type depends on VLE; integer for Moodle)
  312. * @param string $uuid UUID of the avatar
  313. * @param string $avname Name of the avatar
  314. * @return bool True if successful, or false if not.
  315. * @access public
  316. */
  317. function add_linked_avatar($userid, $uuid, $avname, $profilepic = '')
  318. {
  319. // Setup our object
  320. $this->avatar_data = new stdClass();
  321. $this->avatar_data->id = 0;
  322. $this->avatar_data->userid = $userid;
  323. $this->avatar_data->uuid = $uuid;
  324. $this->avatar_data->avname = $avname;
  325. $this->avatar_data->profilepic = $profilepic;
  326. // Add the data to the database
  327. $this->avatar_data->id = sloodle_insert_record('sloodle_users', $this->avatar_data);
  328. if (!$this->avatar_data->id) {
  329. $this->avatar_data = null;
  330. return false;
  331. }
  332. // Delete any pending avatars with the same details
  333. sloodle_delete_records('sloodle_pending_avatars', 'uuid', $uuid, 'avname', $avname);
  334. return true;
  335. }
  336. /**
  337. * Adds a new unlinked avatar to the database (the entry is pending linking)
  338. * @param string $uuid UUID of the avatar
  339. * @param string $avname Name of the avatar
  340. * @param int $timestamp The timestamp at which to mark the update (or null to use the current timestamp). Entries expire after a certain period.
  341. * @return object|bool Returns the database object if successul, or false if not.
  342. * @access public
  343. */
  344. function add_pending_avatar($uuid, $avname, $timestamp = null)
  345. {
  346. // Setup the timestamp
  347. if ($timestamp == null) $timestamp = time();
  348. // Setup our object
  349. $pending_avatar = new stdClass();
  350. $pending_avatar->id = 0;
  351. $pending_avatar->uuid = $uuid;
  352. $pending_avatar->avname = $avname;
  353. $pending_avatar->lst = sloodle_random_security_token();
  354. $pending_avatar->timeupdated = $timestamp;
  355. // Add the data to the database
  356. $pending_avatar->id = sloodle_insert_record('sloodle_pending_avatars', $pending_avatar);
  357. if (!$pending_avatar->id) {
  358. return false;
  359. }
  360. return $pending_avatar;
  361. }
  362. /**
  363. * Auto-register a new user account for the current avatar.
  364. * NOTE: this does NOT respect ANYTHING but the most basic Moodle accounts.
  365. * Use at your own risk!
  366. * @return string|bool The new password (plaintext) if successful, or false if not
  367. * @access public
  368. */
  369. function autoregister_avatar_user()
  370. {
  371. global $CFG;
  372. // Make sure we have avatar data, and reset the user data
  373. if (empty($this->avatar_data)) return false;
  374. $this->user_data = null;
  375. // Construct a basic username
  376. $nameparts = explode(' ', $this->avatar_data->avname);
  377. $baseusername = strip_tags(stripslashes(implode('', $nameparts)));
  378. $username = $baseusername;
  379. $conflict_moodle = sloodle_record_exists('user', 'username', $username);
  380. // If that didn't work, then try a few random variants (just a number added to the end of the name)
  381. $MAX_RANDOM_TRIES = 3;
  382. $rnd_try = 0;
  383. while ($rnd_try < $MAX_RANDOM_TRIES && $conflict_moodle) {
  384. // Pick a random 3 digit number
  385. $rnd_num = mt_rand(100, 998);
  386. if ($rnd_num >= 666) $rnd_num++; // Some users may object to this number
  387. // Construct a new username to try
  388. $username = $baseusername . (string)$rnd_num;
  389. // Check for conflicts
  390. $conflict_moodle = sloodle_record_exists('user', 'username', $username);
  391. // Next attempt
  392. $rnd_try++;
  393. }
  394. // Stop if we haven't found a unique name
  395. if ($conflict_moodle) return false;
  396. // Looks like we got an OK username
  397. // Generate a random password
  398. $plain_password = sloodle_random_web_password();
  399. // Create the new user
  400. $this->user_data = create_user_record($username, $plain_password);
  401. if (!$this->user_data) {
  402. $this->user_data = null;
  403. return false;
  404. }
  405. // Get the complete user data again, so that we have the password this time
  406. $this->user_data = get_complete_user_data('id', $this->user_data->id);
  407. // Attempt to use the first and last names of the avatar
  408. $this->user_data->firstname = $nameparts[0];
  409. if (isset($nameparts[1])) $this->user_data->lastname = $nameparts[1];
  410. else $this->user_data->lastname = $nameparts[0];
  411. // Prevent emails from being sent to this user
  412. $this->user_data->emailstop = 1;
  413. // Attempt to update the database (we don't really care if this fails, since everything else will have worked)
  414. sloodle_update_record('user', $this->user_data);
  415. // Now link the avatar to this account
  416. $this->avatar_data->userid = $this->user_data->id;
  417. sloodle_update_record('sloodle_users', $this->avatar_data);
  418. return $plain_password;
  419. }
  420. /**
  421. * Load the avatar linked to the current user.
  422. * @return bool,string True if a link was loaded, false if there was no link, or string 'multi' if multiple avatars are linked
  423. * @access public
  424. */
  425. function load_linked_avatar()
  426. {
  427. // Make sure we have some user data
  428. if (empty($this->user_data)) return false;
  429. $this->avatar_data = null;
  430. // Fetch all avatar records which are linked to the user
  431. $recs = sloodle_get_records('sloodle_users', 'userid', $this->user_data->id);
  432. if (!is_array($recs)) return false;
  433. if (!count($recs)) return false;
  434. if (count($recs) > 1) return 'multi';
  435. // Store the avatar data
  436. reset($recs);
  437. $this->avatar_data = current($recs);
  438. return true;
  439. }
  440. /**
  441. * Find the VLE user linked to the current avatar.
  442. * @return bool True if successful, or false if no link was found
  443. * @access public
  444. */
  445. function load_linked_user()
  446. {
  447. // Make sure we have some avatar data
  448. if (empty($this->avatar_data)) return false;
  449. // Fetch the user data
  450. $this->user_data = get_complete_user_data('id', $this->avatar_data->userid);
  451. if ($this->user_data) return true;
  452. return false;
  453. }
  454. ///// LOGIN FUNCTIONS /////
  455. /**
  456. * Internally 'log-in' the current user.
  457. * In Moodle, this just stores all the user data in the global $USER variable.
  458. * This function will not perform automatic registration.
  459. * @return bool True if successful, or false otherwise.
  460. * @access public
  461. */
  462. function login()
  463. {
  464. global $USER;
  465. // Make sure we have some user data
  466. if (empty($this->user_data)) return false;
  467. $USER = get_complete_user_data('id', $this->user_data->id);
  468. return true;
  469. }
  470. ///// COURSE FUNCTIONS /////
  471. /**
  472. * Gets a numeric array of {@link SloodleCourse} objects for courses the user is enrolled in.
  473. * WARNING: this function is not very efficient, and will likely be very slow on large sites.
  474. * @param mixed $category Unique identifier of a category to limit the query to. Ignored if null. (Type depends on VLE; integer for Moodle)
  475. * @return array A numeric array of {@link SloodleCourse} objects
  476. * @access public
  477. */
  478. function get_enrolled_courses($category = null)
  479. {
  480. // Make sure we have user data
  481. if (empty($this->user_data)) return array();
  482. // If it is the guess user, then they are not enrolled at all
  483. if (isguestuser($this->user_data->id)) return array();
  484. // Convert the category ID as appropriate
  485. if ($category == null || $category < 0 || !is_int($category)) $category = 0;
  486. // Modified from "get_user_capability_course()" in Moodle's "lib/accesslib.php"
  487. // Get a list of all courses on the system
  488. $usercourses = array();
  489. $courses = get_courses($category);
  490. // Go through each course
  491. foreach ($courses as $course) {
  492. // Check if the user can view this course and is not a guest in it.
  493. // (Note: the site course is always available to all users.)
  494. $course_context = get_context_instance(CONTEXT_COURSE, $course->id);
  495. if ($course->id == SITEID || (has_capability('mod/sloodle:courseparticipate', $course_context, $this->user_data->id) )) {
  496. $sc = new SloodleCourse();
  497. $sc->load($course);
  498. $usercourses[] = $sc;
  499. }
  500. }
  501. return $usercourses;
  502. }
  503. /**
  504. * Gets a numeric array of {@link SloodleCourse} objects for courses the user is Sloodle staff.
  505. * This relates to the "mod/sloodle:staff" capability.
  506. * WARNING: this function is not very efficient, and will likely be very slow on large sites.
  507. * @param mixed $category Unique identifier of a category to limit the query to. Ignored if null. (Type depends on VLE; integer for Moodle)
  508. * @return array A numeric array of {@link SloodleCourse} objects
  509. * @access public
  510. */
  511. function get_staff_courses($category = null)
  512. {
  513. // Make sure we have user data
  514. if (empty($this->user_data)) return array();
  515. // Convert the category ID as appropriate
  516. if ($category == null || $category < 0 || !is_int($category)) $category = 0;
  517. // Modified from "get_user_capability_course()" in Moodle's "lib/accesslib.php"
  518. // Get a list of all courses on the system
  519. $usercourses = array();
  520. $courses = get_courses($category);
  521. // Go through each course
  522. foreach ($courses as $course) {
  523. // Check if the user can teach using Sloodle on this course
  524. if (has_capability('mod/sloodle:staff', get_context_instance(CONTEXT_COURSE, $course->id), $this->user_data->id)) {
  525. $sc = new SloodleCourse();
  526. $sc->load($course);
  527. $usercourses[] = $sc;
  528. }
  529. }
  530. return $usercourses;
  531. }
  532. /**
  533. * is_really_enrolled checks if the current user is enrolled in the course. The other is_enrolled function
  534. * evaluates to true for administrators even if they are not enrolled in the course. This function will
  535. * evaluate to false for administrators
  536. * @param $courseid [integer] the id of the course
  537. */
  538. function is_really_enrolled($courseid)
  539. {
  540. global $USER;
  541. global $CFG;
  542. $sql = "SELECT u.id, u.username FROM ".$CFG->prefix."user u, ".$CFG->prefix."role_assignments r";
  543. $sql .= " WHERE u.id = r.userid";
  544. $sql .= " AND r.contextid = ? AND u.id=?";
  545. return sloodle_get_records_sql_params($sql, array($courseid, $USER->id));
  546. }
  547. /**
  548. * Is the current user enrolled in the specified course?
  549. * NOTE: a side effect of this is that it logs-in the user
  550. * @param mixed $course Unique identifier of the course -- type depends on VLE (integer for Moodle)
  551. * @param bool True if the user is enrolled, or false if not.
  552. * @access public
  553. * @todo Update to match parameter format and handling of {@link enrol()} function.
  554. */
  555. function is_enrolled($courseid)
  556. {
  557. global $USER;
  558. // Attempt to log-in the user
  559. if (!$this->login()) return false;
  560. // NOTE: this stuff was lifted from the Moodle 1.8 "course/enrol.php" script
  561. // Create a context for this course
  562. if (!$context = get_context_instance(CONTEXT_COURSE, $courseid)) return false;
  563. // Ensure we have up-to-date capabilities for the current user
  564. load_all_capabilities();
  565. // Check if the user can view the course, and does not simply have guest access to it
  566. // Allow the site course
  567. return ($courseid == SITEID || (has_capability('mod/sloodle:courseparticipate', $context) ));
  568. }
  569. /**
  570. * Is the current user Sloodle staff in the specified course?
  571. * NOTE: a side effect of this is that it logs-in the user
  572. * @param mixed $course Unique identifier of the course -- type depends on VLE (integer for Moodle)
  573. * @param bool True if the user is staff, or false if not.
  574. * @access public
  575. * @todo Update to match parameter format and handling of {@link enrol()} function.
  576. */
  577. function is_staff($courseid)
  578. {
  579. global $USER;
  580. // Attempt to log-in the user
  581. if (!$this->login()) return false;
  582. // NOTE: this stuff was lifted from the Moodle 1.8 "course/enrol.php" script
  583. // Create a context for this course
  584. if (!$context = get_context_instance(CONTEXT_COURSE, $courseid)) return false;
  585. // Ensure we have up-to-date capabilities for the current user
  586. load_all_capabilities();
  587. // Check if the user can view the course, does not simply have guest access to it, *and* is staff
  588. return (has_capability('mod/sloodle:courseparticipate', $context) && has_capability('mod/sloodle:staff', $context));
  589. }
  590. /**
  591. * Enrols the current user in the specified course
  592. * NOTE: a side effect of this is that it logs-in the user
  593. * @param object $sloodle_course A {@link SloodleCourse} object setup for the necessary course. If null, then the {@link $_session} member is queried instead.
  594. * @param bool True if successful (or the user was already enrolled), or false otherwise
  595. * @access public
  596. */
  597. function enrol($sloodle_course = null)
  598. {
  599. SloodleDebugLogger::log('DEBUG', "in enrol()");
  600. global $USER, $CFG;
  601. // Attempt to log-in the user
  602. if (!$this->login()) return false;
  603. // Was course data provided?
  604. if (empty($sloodle_course)) {
  605. // No - attempt to get some from the Sloodle session
  606. if (empty($this->_session)) return false;
  607. if (empty($this->_session->course)) return false;
  608. $sloodle_course = $this->_session->course;
  609. }
  610. // NOTE: much of this stuff was lifted from the Moodle 1.8 "course/enrol.php" script
  611. // Fetch the Moodle course data, and a course context
  612. $course = $sloodle_course->get_course_object();
  613. if (!$context = get_context_instance(CONTEXT_COURSE, $course->id)) return false;
  614. // Ensure we have up-to-date capabilities for the current user
  615. load_all_capabilities();
  616. // Check if the user can view the course, and does not simply have guest access to it
  617. // (No point trying to enrol somebody if they are already enrolled!)
  618. if (has_capability('mod/sloodle:courseparticipate', $context) ) return true;
  619. // Make sure auto-registration is enabled for this site/course, and that the controller (if applicable) is enabled
  620. if (!$sloodle_course->check_autoreg()) return false;
  621. // Can't enrol users on meta courses or the site course
  622. if ($course->metacourse || $course->id == SITEID) return false;
  623. // Is there an enrolment period in effect?
  624. if ($course->enrolperiod) {
  625. if ($roles = get_user_roles($context, $USER->id)) {
  626. foreach ($roles as $role) {
  627. if ($role->timestart && ($role->timestart >= time())) {
  628. return false;
  629. }
  630. }
  631. }
  632. }
  633. if (SLOODLE_IS_ENVIRONMENT_MOODLE_2) {
  634. $plugins = enrol_get_plugins(true);
  635. $enrolinstances = enrol_get_instances($course->id, true);
  636. foreach($enrolinstances as $instance) {
  637. if (!isset($plugins[$instance->enrol])) {
  638. continue;
  639. }
  640. if ($instance->enrol === 'guest') {
  641. // blacklist known temporary guest plugins
  642. continue;
  643. }
  644. $plugin = $plugins[$instance->enrol];
  645. if ($plugin->show_enrolme_link($instance)) {
  646. $plugin->enrol_user($instance, $USER->id, $instance->roleid); // TODO: Moodle doesn't seem to want to tell us whether this worked or not. Maybe we could check somehow?
  647. add_to_log($course->id, 'sloodle', 'update', '', 'auto-enrolment');
  648. return true;
  649. }
  650. }
  651. } else {
  652. SloodleDebugLogger::log('DEBUG', "Doing Moodle 1 enrolment checks");
  653. // Make sure the course is enrollable
  654. if (!$course->enrollable ||
  655. ($course->enrollable == 2 && $course->enrolstartdate > 0 && $course->enrolstartdate > time()) ||
  656. ($course->enrollable == 2 && $course->enrolenddate > 0 && $course->enrolenddate <= time())
  657. ) {
  658. return false;
  659. }
  660. if (!enrol_into_course($course, $USER, 'manual')) return false;
  661. add_to_log($course->id, 'sloodle', 'update', '', 'auto-enrolment');
  662. return true;
  663. }
  664. }
  665. ///// PASSWORD /////
  666. /**
  667. * Resets the user's password
  668. * @param bool $require If true, then the script will be terminated if the operation fails
  669. * @return string|bool The new password if successful, or false otherwise (if $require was false).
  670. */
  671. function reset_password($require = true)
  672. {
  673. // Check that the user is loaded
  674. if (empty($this->user_data)) {
  675. if ($require) {
  676. $this->_session->response->quick_output(-301, 'USER_AUTH', 'User data not loaded', false);
  677. exit();
  678. }
  679. return false;
  680. }
  681. // If the user has an email address on file, then we can't reset the password
  682. if (!empty($this->user_data->email)) {
  683. if ($require) {
  684. $this->_session->response->quick_output(-341, 'USER_AUTH', 'User has email address in database. Cannot use Sloodle password reset.', false);
  685. exit();
  686. }
  687. return false;
  688. }
  689. // Generate a new random password
  690. $password = sloodle_random_web_password();
  691. // Update the user's password data
  692. if (!update_internal_user_password($this->user_data, $password)) {
  693. if ($require) {
  694. $this->_session->response->quick_output(-103, 'SYSTEM', 'Failed to update user password', false);
  695. exit();
  696. }
  697. return false;
  698. }
  699. return $password;
  700. }
  701. /**
  702. * If the system is waiting to send a password notification to this user, then remove it
  703. * @return void
  704. */
  705. function purge_password_notifications()
  706. {
  707. // Check that the user is loaded
  708. if (empty($this->user_data)) return;
  709. // Delete the database entries
  710. sloodle_delete_records('sloodle_login_notifications', 'username', $this->user_data->username);
  711. }
  712. ///// USER-CENTRIC OBJECTS /////
  713. /**
  714. * Authorises the given object for the current avatar.
  715. * Note: the object must already exist in the database.
  716. * @param int $authid The ID of the authorisation entry
  717. * @return bool True if successful, or false otherwise
  718. */
  719. function authorise_user_object($authid)
  720. {
  721. // Make sure an avatar is loaded
  722. if (!$this->is_avatar_loaded()) return false;
  723. // Does the object already exist in the database?
  724. $auth = sloodle_get_record('sloodle_user_object', 'id', $authid, 'avuuid', $this->get_avatar_uuid());
  725. if (!$auth) return false;
  726. // Update the existing record
  727. $auth->authorised = 1;
  728. $auth->timeupdated = time();
  729. return sloodle_update_record('sloodle_user_object', $auth);
  730. }
  731. /**
  732. * Adds or udpates the given user object as unauthorised.
  733. * (This function can be called statically).
  734. * @param string $avuuid UUID of the avatar the object will be authorised for
  735. * @param string $objuuid UUID of the object
  736. * @param string $objname Name of the object
  737. * @param string $password Password to store for the object
  738. * @return int|bool Integer ID of the authorisation entry, or false otherwise
  739. */
  740. function add_user_object($avuuid, $objuuid, $objname, $password)
  741. {
  742. // Make sure our other parameters are valid
  743. if (empty($objuuid) || empty($password)) return false;
  744. // Does the object already exist in the database?
  745. $auth = sloodle_get_record('sloodle_user_object', 'objuuid', $objuuid);
  746. $success = false;
  747. if (!$auth) {
  748. // No - insert a new record
  749. $auth = new stdClass();
  750. $auth->avuuid = $avuuid;
  751. $auth->objuuid = $objuuid;
  752. $auth->objname = $objname;
  753. $auth->password = $password;
  754. $auth->authorised = 0;
  755. $auth->timeupdated = time();
  756. $success = sloodle_insert_record('sloodle_user_object', $auth);
  757. } else {
  758. // Yes - update the existing record
  759. $auth->avuuid = $avuuid;
  760. $auth->objuuid = $objuuid;
  761. $auth->objname = $objname;
  762. $auth->password = $password;
  763. $auth->authorised = 0;
  764. $auth->timeupdated = time();
  765. if (sloodle_update_record('sloodle_user_object', $auth)) $success = $auth->id;
  766. }
  767. return $success;
  768. }
  769. /**
  770. * Gets a list of all user-centric objects authorised for the current avatar.
  771. * @return array A numeric array of {@link SloodleUserObject} objects
  772. */
  773. function get_user_objects()
  774. {
  775. // Make sure an avatar is loaded
  776. if (!$this->is_avatar_loaded()) return array();
  777. // Get all objects authorised for this avatar's UUID
  778. $recs = sloodle_get_records('sloodle_user_object', 'avuuid', $this->get_avatar_uuid());
  779. if (!$recs) return array();
  780. // Construct an array of SloodleUserObject's
  781. $output = array();
  782. foreach ($recs as $r) {
  783. $obj = new SloodleUserObject();
  784. $obj->id = $r->id;
  785. $obj->avuuid = $r->avuuid;
  786. $obj->objuuid = $r->objuuid;
  787. $obj->objname = $r->objname;
  788. $obj->password = $r->password;
  789. $obj->authorized = (bool)$r->authorised; // Note different spelling... oops! -PB
  790. $obj->timeupdated = $r->timeupdated;
  791. $output[] = $obj;
  792. }
  793. return $output;
  794. }
  795. /**
  796. * Deletes a user-centric object by UUID.
  797. * Note: the object must have been authorised for the current avatar.
  798. * @param string $uuid The UUID of the object to delete
  799. * @return void
  800. */
  801. function delete_user_object($uuid)
  802. {
  803. if (!$this->is_avatar_loaded()) return;
  804. sloodle_delete_records('sloodle_user_object', 'avuuid', $this->get_avatar_uuid(), 'objuuid', $uuid);
  805. }
  806. /*
  807. Static function returning a hash of userids to avatar names of admin users.
  808. This is useful if you want to know everyone who may be able to user a course
  809. */
  810. function SiteAdminUserIDsToAvatarNames() {
  811. global $CFG;
  812. if (!$site_admin_list = $CFG->siteadmins) {
  813. return array();
  814. }
  815. $site_admin_ids = explode(',',$site_admin_list);
  816. if (count($site_admin_ids) == 0) {
  817. return array();
  818. }
  819. // We'll just loop through them. In theory this could be more efficient, but there's probably only one site admin.
  820. $users = array();
  821. foreach($site_admin_ids as $id) {
  822. if ($rec = sloodle_get_record('sloodle_users', 'userid', $id)) {
  823. $users[$rec->userid] = $rec->avname;
  824. }
  825. }
  826. return $users;
  827. }
  828. /*
  829. Static function returning a hash of userids to avatar names of admin users.
  830. This is useful if you want to know everyone who may be able to user a course
  831. */
  832. function AvatarUUIDForUserID($userid) {
  833. if ($rec = sloodle_get_record('sloodle_users', 'userid', $userid)) {
  834. return $rec->avuuid;
  835. }
  836. return 0;
  837. }
  838. }
  839. ?>