PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/app/models/ca_users.php

https://bitbucket.org/Sinfin/pawtucket
PHP | 2297 lines | 1446 code | 156 blank | 695 comment | 350 complexity | 665a6c9af652c8638df6e6504b19add0 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /** ---------------------------------------------------------------------
  3. * app/models/ca_users.php : table access class for table ca_users
  4. * ----------------------------------------------------------------------
  5. * CollectiveAccess
  6. * Open-source collections management software
  7. * ----------------------------------------------------------------------
  8. *
  9. * Software by Whirl-i-Gig (http://www.whirl-i-gig.com)
  10. * Copyright 2008-2011 Whirl-i-Gig
  11. *
  12. * For more information visit http://www.CollectiveAccess.org
  13. *
  14. * This program is free software; you may redistribute it and/or modify it under
  15. * the terms of the provided license as published by Whirl-i-Gig
  16. *
  17. * CollectiveAccess is distributed in the hope that it will be useful, but
  18. * WITHOUT ANY WARRANTIES whatsoever, including any implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  20. *
  21. * This source code is free and modifiable under the terms of
  22. * GNU General Public License. (http://www.gnu.org/copyleft/gpl.html). See
  23. * the "license.txt" file for details, or visit the CollectiveAccess web site at
  24. * http://www.CollectiveAccess.org
  25. *
  26. * @package CollectiveAccess
  27. * @subpackage models
  28. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License version 3
  29. *
  30. * ----------------------------------------------------------------------
  31. */
  32. /**
  33. *
  34. */
  35. require_once(__CA_LIB_DIR__."/core/AccessRestrictions.php");
  36. require_once(__CA_APP_DIR__.'/models/ca_user_roles.php');
  37. include_once(__CA_APP_DIR__."/helpers/utilityHelpers.php");
  38. require_once(__CA_APP_DIR__.'/models/ca_user_groups.php');
  39. require_once(__CA_APP_DIR__.'/models/ca_locales.php');
  40. BaseModel::$s_ca_models_definitions['ca_users'] = array(
  41. 'NAME_SINGULAR' => _t('user'),
  42. 'NAME_PLURAL' => _t('users'),
  43. 'FIELDS' => array(
  44. 'user_id' => array(
  45. 'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_HIDDEN,
  46. 'IDENTITY' => true, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  47. 'IS_NULL' => false,
  48. 'DEFAULT' => '',
  49. 'LABEL' => 'User id', 'DESCRIPTION' => 'Identifier for User'
  50. ),
  51. 'user_name' => array(
  52. 'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD,
  53. 'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
  54. 'IS_NULL' => false,
  55. 'DEFAULT' => '',
  56. 'LABEL' => _t('User name'), 'DESCRIPTION' => _t('The login name for this user. This name is used in combination with the password set below to access the system.'),
  57. 'BOUNDS_LENGTH' => array(1,255)
  58. ),
  59. 'userclass' => array(
  60. 'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_SELECT,
  61. 'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
  62. 'IS_NULL' => false,
  63. 'DEFAULT' => 0,
  64. 'LABEL' => _t('User class'), 'DESCRIPTION' => _t('"Full" user accounts may log into all CollectiveAccess interfaces. "Public" user accounts may only log into the publicly accessible front-end system (if one exists). "Deleted" users may not log into any interface – the account is considered removed.'),
  65. "BOUNDS_CHOICE_LIST"=> array(
  66. _t('full-access') => 0,
  67. _t('public-access only') => 1,
  68. _t('deleted') => 255
  69. )
  70. ),
  71. 'password' => array(
  72. 'FIELD_TYPE' => FT_PASSWORD, 'DISPLAY_TYPE' => DT_FIELD,
  73. 'DISPLAY_WIDTH' => 60, 'DISPLAY_HEIGHT' => 1,
  74. 'IS_NULL' => false,
  75. 'DEFAULT' => '',
  76. 'LABEL' => _t('Password'), 'DESCRIPTION' => _t('The login password for this user. Passwords must be at least 4 characters and should ideally contain a combination of letters and numbers. Passwords are case-sensitive.'),
  77. 'BOUNDS_LENGTH' => array(4,100)
  78. ),
  79. 'fname' => array(
  80. 'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD,
  81. 'DISPLAY_WIDTH' => 60, 'DISPLAY_HEIGHT' => 1,
  82. 'IS_NULL' => false,
  83. 'DEFAULT' => '',
  84. 'LABEL' => _t('First name'), 'DESCRIPTION' => _t('The forename of this user.'),
  85. 'BOUNDS_LENGTH' => array(1,255)
  86. ),
  87. 'lname' => array(
  88. 'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD,
  89. 'DISPLAY_WIDTH' => 60, 'DISPLAY_HEIGHT' => 1,
  90. 'IS_NULL' => false,
  91. 'DEFAULT' => '',
  92. 'LABEL' => _t('Last name'), 'DESCRIPTION' => _t('The surname of this user.'),
  93. 'BOUNDS_LENGTH' => array(1,255)
  94. ),
  95. 'email' => array(
  96. 'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD,
  97. 'DISPLAY_WIDTH' => 60, 'DISPLAY_HEIGHT' => 1,
  98. 'IS_NULL' => false,
  99. 'DEFAULT' => '',
  100. 'LABEL' => _t('E-mail'), 'DESCRIPTION' => _t('The e-mail address of this user. The address will be used for all mail-based system notifications and alerts to this user.'),
  101. 'BOUNDS_LENGTH' => array(0,255)
  102. ),
  103. 'vars' => array(
  104. 'FIELD_TYPE' => FT_VARS, 'DISPLAY_TYPE' => DT_OMIT,
  105. 'DISPLAY_WIDTH' => 88, 'DISPLAY_HEIGHT' => 15,
  106. 'IS_NULL' => false,
  107. 'DEFAULT' => '',
  108. 'LABEL' => 'User variable storage', 'DESCRIPTION' => 'Storage area for user variables'
  109. ),
  110. 'volatile_vars' => array(
  111. 'FIELD_TYPE' => FT_VARS, 'DISPLAY_TYPE' => DT_OMIT,
  112. 'DISPLAY_WIDTH' => 88, 'DISPLAY_HEIGHT' => 15,
  113. 'IS_NULL' => false,
  114. 'DEFAULT' => '',
  115. 'LABEL' => 'Volatile user variable storage', 'DESCRIPTION' => 'Storage area for user variables of limited size that change often'
  116. ),
  117. 'active' => array(
  118. 'FIELD_TYPE' => FT_BIT, 'DISPLAY_TYPE' => DT_CHECKBOXES,
  119. 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  120. 'IS_NULL' => false,
  121. 'DEFAULT' => '',
  122. 'LABEL' => _t('Account is activated?'), "DESCRIPTION" => "If checked, indicates user account is active. Only active users are allowed to log into the system.",
  123. 'BOUNDS_VALUE' => array(0,1)
  124. ),
  125. 'confirmed_on' => array(
  126. 'FIELD_TYPE' => FT_DATETIME, 'DISPLAY_TYPE' => DT_OMIT,
  127. 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
  128. 'IS_NULL' => true,
  129. 'DEFAULT' => '',
  130. 'LABEL' => _t('Confirmed on'), 'DESCRIPTION' => _t('Confirmed on')
  131. ),
  132. 'confirmation_key' => array(
  133. 'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_OMIT,
  134. 'DISPLAY_WIDTH' => 32, 'DISPLAY_HEIGHT' => 1,
  135. 'IS_NULL' => true,
  136. 'DEFAULT' => '',
  137. 'LABEL' => _t('Confirmation key'), 'DESCRIPTION' => _t('Confirmation key used for email verification.'),
  138. 'BOUNDS_LENGTH' => array(0,32)
  139. )
  140. )
  141. );
  142. class ca_users extends BaseModel {
  143. # ---------------------------------
  144. # --- Object attribute properties
  145. # ---------------------------------
  146. # Describe structure of content object's properties - eg. database fields and their
  147. # associated types, what modes are supported, et al.
  148. #
  149. private $_user_pref_defs;
  150. # ------------------------------------------------------
  151. # --- Basic object parameters
  152. # ------------------------------------------------------
  153. # what table does this class represent?
  154. protected $TABLE = 'ca_users';
  155. # what is the primary key of the table?
  156. protected $PRIMARY_KEY = 'user_id';
  157. # ------------------------------------------------------
  158. # --- Properties used by standard editing scripts
  159. #
  160. # These class properties allow generic scripts to properly display
  161. # records from the table represented by this class
  162. #
  163. # ------------------------------------------------------
  164. # Array of fields to display in a listing of records from this table
  165. protected $LIST_FIELDS = array('user_name');
  166. # When the list of "list fields" above contains more than one field,
  167. # the LIST_DELIMITER text is displayed between fields as a delimiter.
  168. # This is typically a comma or space, but can be any string you like
  169. protected $LIST_DELIMITER = ' ';
  170. # What you'd call a single record from this table (eg. a "person")
  171. protected $NAME_SINGULAR;
  172. # What you'd call more than one record from this table (eg. "people")
  173. protected $NAME_PLURAL;
  174. # List of fields to sort listing of records by; you can use
  175. # SQL 'ASC' and 'DESC' here if you like.
  176. protected $ORDER_BY = array('user_name');
  177. # Maximum number of record to display per page in a listing
  178. protected $MAX_RECORDS_PER_PAGE = 20;
  179. # How do you want to page through records in a listing: by number pages ordered
  180. # according to your setting above? Or alphabetically by the letters of the first
  181. # LIST_FIELD?
  182. protected $PAGE_SCHEME = 'alpha'; # alpha [alphabetical] or num [numbered pages; default]
  183. # If you want to order records arbitrarily, add a numeric field to the table and place
  184. # its name here. The generic list scripts can then use it to order table records.
  185. protected $RANK = '';
  186. # ------------------------------------------------------
  187. # Hierarchical table properties
  188. # ------------------------------------------------------
  189. protected $HIERARCHY_TYPE = null;
  190. protected $HIERARCHY_LEFT_INDEX_FLD = null;
  191. protected $HIERARCHY_RIGHT_INDEX_FLD = null;
  192. protected $HIERARCHY_PARENT_ID_FLD = null;
  193. protected $HIERARCHY_DEFINITION_TABLE = null;
  194. protected $HIERARCHY_ID_FLD = null;
  195. protected $HIERARCHY_POLY_TABLE = null;
  196. # ------------------------------------------------------
  197. # Change logging
  198. # ------------------------------------------------------
  199. protected $UNIT_ID_FIELD = null;
  200. protected $LOG_CHANGES_TO_SELF = false;
  201. protected $LOG_CHANGES_USING_AS_SUBJECT = array(
  202. "FOREIGN_KEYS" => array(
  203. ),
  204. "RELATED_TABLES" => array(
  205. )
  206. );
  207. /**
  208. * Container for persistent user-specific variables
  209. */
  210. private $opa_user_vars;
  211. private $opa_user_vars_have_changed = false;
  212. /**
  213. * Container for volatile (often changing) persistent user-specific variables
  214. * of limited size. This is meant for storage of values that change on every request. By
  215. * segregating these values from less volatile (and often much larger) user var data we can
  216. * avoid the cost of writing large blocks of data to the database on every request
  217. */
  218. private $opa_volatile_user_vars;
  219. private $opa_volatile_user_vars_have_changed = false;
  220. # ------------------------------------------------------
  221. # Search
  222. # ------------------------------------------------------
  223. protected $SEARCH_CLASSNAME = 'UserSearch';
  224. protected $SEARCH_RESULT_CLASSNAME = 'UserSearchResult';
  225. # ------------------------------------------------------
  226. # $FIELDS contains information about each field in the table. The order in which the fields
  227. # are listed here is the order in which they will be returned using getFields()
  228. protected $FIELDS;
  229. # ------------------------------------------------------
  230. # --- Constructor
  231. #
  232. # This is a function called when a new instance of this object is created. This
  233. # standard constructor supports three calling modes:
  234. #
  235. # 1. If called without parameters, simply creates a new, empty objects object
  236. # 2. If called with a single, valid primary key value, creates a new objects object and loads
  237. # the record identified by the primary key value
  238. #
  239. # ------------------------------------------------------
  240. public function __construct($pn_id=null) {
  241. parent::__construct($pn_id); # call superclass constructor
  242. }
  243. # ----------------------------------------
  244. /**
  245. * Loads user record.
  246. *
  247. * @access public
  248. * @param integer $pm_user_id User id to load. If you pass a string instead of an integer, the record with a user name matching the string will be loaded.
  249. * @return bool Returns true if no error, false if error occurred
  250. */
  251. public function load($pm_user_id=null) {
  252. if (is_numeric($pm_user_id)) {
  253. $vn_rc = parent::load($pm_user_id);
  254. } else {
  255. if (is_array($pm_user_id)) {
  256. $vn_rc = parent::load($pm_user_id);
  257. } else {
  258. $vn_rc = parent::load(array("user_name" => $pm_user_id));
  259. }
  260. }
  261. # load user vars (the get() method automatically unserializes the data)
  262. $this->opa_user_vars = $this->get("vars");
  263. $this->opa_volatile_user_vars = $this->get("volatile_vars");
  264. if (!isset($this->opa_user_vars) || !is_array($this->opa_user_vars)) {
  265. $this->opa_user_vars = array();
  266. }
  267. if (!isset($this->opa_volatile_user_vars) || !is_array($this->opa_volatile_user_vars)) {
  268. $this->opa_volatile_user_vars = array();
  269. }
  270. return $vn_rc;
  271. }
  272. # ----------------------------------------
  273. /**
  274. * Creates new user record. You must set all required user fields before calling this method. If errors occur you can use the standard Table class error handling methods to figure out what went wrong.
  275. *
  276. * Required fields are user_name, password, fname and lname.
  277. *
  278. * @access public
  279. * @return bool Returns true if no error, false if error occurred
  280. */
  281. public function insert($pa_options=null) {
  282. # Confirmation key is an md5 hash than can be used as a confirmation token. The idea
  283. # is that you create a new user record with the 'active' field set to false. You then
  284. # send the confirmation key to the new user (usually via e-mail) and ask them to respond
  285. # with the key. If they do, you know that the e-mail address is valid.
  286. $vs_confirmation_key = md5(tempnam(caGetTempDirPath(),"meow").time().rand(1000, 999999999));
  287. $this->set("confirmation_key", $vs_confirmation_key);
  288. # set user vars (the set() method automatically serializes the vars array)
  289. $this->set("vars",$this->opa_user_vars);
  290. $this->set("volatile_vars",$this->opa_volatile_user_vars);
  291. return parent::insert($pa_options);
  292. }
  293. # ----------------------------------------
  294. /**
  295. * Saves changes to user record. You must make sure all required user fields are set before calling this method. If errors occur you can use the standard Table class error handling methods to figure out what went wrong.
  296. *
  297. * Required fields are user_name, password, fname and lname.
  298. *
  299. * If you do not call this method at the end of your request changed user vars will not be saved! If you are also using the Auth class, the Auth->close() method will call this for you.
  300. *
  301. * @access public
  302. * @return bool Returns true if no error, false if error occurred
  303. */
  304. public function update($pa_options=null) {
  305. $this->clearErrors();
  306. # set user vars (the set() method automatically serializes the vars array)
  307. if ($this->opa_user_vars_have_changed) {
  308. $this->set("vars",$this->opa_user_vars);
  309. }
  310. if ($this->opa_volatile_user_vars_have_changed) {
  311. $this->set("volatile_vars",$this->opa_volatile_user_vars);
  312. }
  313. return parent::update();
  314. }
  315. # ----------------------------------------
  316. /**
  317. * Deletes user. Unlike standard model rows, ca_users rows should never actually be deleted because they need to exist for logging purposes.
  318. * So this version of delete() marks the row as deleted by setting ca_users.userclass = 255 and *not* invoking to BaseModel::delete()
  319. * @access public
  320. * @return bool Returns true if no error, false if error occurred
  321. */
  322. // PM: added args to fix Strict error
  323. // public function delete($delete_related=0, $pa_fields=null, $pa_table_list=null) {
  324. public function delete() {
  325. $this->clearErrors();
  326. $this->set('userclass', 255);
  327. return $this->update();
  328. }
  329. # ----------------------------------------
  330. # --- Authentication
  331. # ----------------------------------------
  332. /**
  333. * Returns true if the provided clear-text password ($ps_password) is valid for the currently loaded record.
  334. *
  335. * Note: If "user_old_style_passwords" configuration directive is set to a non-blank, non-zero
  336. * value in the application configuration file, passwords are encrypted using the PHP crypt() function. Otherwise
  337. * the md5 hash of the clear-text password is used.
  338. *
  339. * @access public
  340. * @param string $ps_password Clear-text password
  341. * @return bool Returns true if password is valid, false if not
  342. */
  343. # Returns true if password (clear text) is correct for the current user
  344. public function verify($ps_password) {
  345. return (md5($ps_password) == $this->get("password")) ? true : false;
  346. }
  347. # ----------------------------------------
  348. # --- User variables
  349. # ----------------------------------------
  350. /**
  351. * Sets user variable. User variables are names ("keys") with associated values (strings, numbers or arrays).
  352. * Once a user variable is set its value persists across instantiations until deleted or changed.
  353. *
  354. * Changes to user variables are saved when the insert() (for new user records) or update() (for existing user records)
  355. * method is called. If you do not call either of these any changes will be lost when the request completes.
  356. *
  357. * @access public
  358. * @param string $ps_key Name of user variable
  359. * @param mixed $pm_val Value of user variable. Can be string, number or array.
  360. * @param array $pa_options Associative array of options. Support options are:
  361. * - ENTITY_ENCODE_INPUT = Convert all "special" HTML characters in variable value to entities; default is true
  362. * - URL_ENCODE_INPUT = Url encodes variable value; default is false
  363. * @return bool Returns true on successful save, false if the variable name or value was invalid
  364. */
  365. public function setVar ($ps_key, $pm_val, $pa_options=null) {
  366. if (is_object($pm_val)) { return false; }
  367. if (!is_array($pa_options)) { $pa_options = array(); }
  368. $this->clearErrors();
  369. if ($ps_key) {
  370. if (isset($pa_options['volatile']) && $pa_options['volatile']) {
  371. $va_vars =& $this->opa_volatile_user_vars;
  372. $vb_has_changed =& $this->opa_volatile_user_vars_have_changed;
  373. unset($this->opa_user_vars[$ps_key]);
  374. } else {
  375. $va_vars =& $this->opa_user_vars;
  376. $vb_has_changed =& $this->opa_user_vars_have_changed;
  377. unset($this->opa_volatile_user_vars_have_changed[$ps_key]);
  378. }
  379. if (isset($pa_options["ENTITY_ENCODE_INPUT"]) && $pa_options["ENTITY_ENCODE_INPUT"]) {
  380. if (is_string($pm_val)) {
  381. $vs_proc_val = htmlentities(html_entity_decode($pm_val));
  382. } else {
  383. $vs_proc_val = $pm_val;
  384. }
  385. } else {
  386. if (isset($pa_options["URL_ENCODE_INPUT"]) && $pa_options["URL_ENCODE_INPUT"]) {
  387. $vs_proc_val = urlencode($pm_val);
  388. } else {
  389. $vs_proc_val = $pm_val;
  390. }
  391. }
  392. if (
  393. (
  394. (is_array($vs_proc_val) && !is_array($va_vars[$ps_key]))
  395. ||
  396. (!is_array($vs_proc_val) && is_array($va_vars[$ps_key]))
  397. ||
  398. (is_array($vs_proc_val) && (is_array($va_vars[$ps_key])) && (sizeof($vs_proc_val) != sizeof($va_vars[$ps_key])))
  399. ||
  400. (md5(print_r($vs_proc_val, true)) != md5(print_r($va_vars[$ps_key], true)))
  401. )
  402. ) {
  403. $vb_has_changed = true;
  404. $va_vars[$ps_key] = $vs_proc_val;
  405. } else {
  406. if ((string)$vs_proc_val != (string)$va_vars[$ps_key]) {
  407. $vb_has_changed = true;
  408. $va_vars[$ps_key] = $vs_proc_val;
  409. }
  410. }
  411. return true;
  412. }
  413. return false;
  414. }
  415. # ----------------------------------------
  416. /**
  417. * Deletes user variable. Once deleted, you must call insert() (for new user records) or update() (for existing user records)
  418. * to make the deletion permanent.
  419. *
  420. * @access public
  421. * @param string $ps_key Name of user variable
  422. * @return bool Returns true if variable was defined, false if it didn't exist
  423. */
  424. public function deleteVar ($ps_key) {
  425. $this->clearErrors();
  426. if (isset($this->opa_user_vars[$ps_key])) {
  427. unset($this->opa_user_vars[$ps_key]);
  428. $this->opa_user_vars_have_changed = true;
  429. return true;
  430. } else {
  431. if (isset($this->opa_volatile_user_vars[$ps_key])) {
  432. unset($this->opa_volatile_user_vars[$ps_key]);
  433. $this->opa_volatile_user_vars_have_changed = true;
  434. return true;
  435. } else {
  436. return false;
  437. }
  438. }
  439. }
  440. # ----------------------------------------
  441. /**
  442. * Returns value of user variable. Returns null if variable does not exist.
  443. *
  444. * @access public
  445. * @param string $ps_key Name of user variable
  446. * @return mixed Value of variable (string, number or array); null is variable is not defined.
  447. */
  448. public function getVar ($ps_key) {
  449. $this->clearErrors();
  450. if (isset($this->opa_user_vars[$ps_key])) {
  451. return (is_array($this->opa_user_vars[$ps_key])) ? $this->opa_user_vars[$ps_key] : stripSlashes($this->opa_user_vars[$ps_key]);
  452. } else {
  453. if (isset($this->opa_volatile_user_vars[$ps_key])) {
  454. return (is_array($this->opa_volatile_user_vars[$ps_key])) ? $this->opa_volatile_user_vars[$ps_key] : stripSlashes($this->opa_volatile_user_vars[$ps_key]);
  455. }
  456. }
  457. return null;
  458. }
  459. # ----------------------------------------
  460. /**
  461. * Returns list of user variable names
  462. *
  463. * @access public
  464. * @return array Array of uservar names, or empty array if none are defined
  465. */
  466. public function getVarKeys() {
  467. $va_keys = array();
  468. if (isset($this->opa_user_vars) && is_array($this->opa_user_vars)) {
  469. $va_keys = array_keys($this->opa_user_vars);
  470. }
  471. if (isset($this->opa_volatile_user_vars) && is_array($this->opa_volatile_user_vars)) {
  472. $va_keys = array_merge($va_keys, array_keys($this->opa_volatile_user_vars));
  473. }
  474. return $va_keys;
  475. }
  476. # ----------------------------------------
  477. /**
  478. * Returns list of users
  479. *
  480. * @param array $pa_options Optional array of options. Options include:
  481. * sort
  482. * sort_direction
  483. * userclass
  484. * @return array List of users. Array is keyed on user_id and value is array with all ca_users fields + the last_login time as a unix timestamp
  485. *
  486. */
  487. public function getUserList($pa_options=null) {
  488. $ps_sort_field= isset($pa_options['sort']) ? $pa_options['sort'] : '';
  489. $ps_sort_direction= isset($pa_options['sort_direction']) ? $pa_options['sort_direction'] : 'asc';
  490. $pa_userclass= isset($pa_options['userclass']) ? $pa_options['userclass'] : array();
  491. if(!is_array($pa_userclass)) { $pa_userclass = array($pa_userclass); }
  492. $o_db = $this->getDb();
  493. $va_valid_sorts = array('lname,fname', 'user_name', 'email', 'last_login', 'active');
  494. if (!in_array($ps_sort_field, $va_valid_sorts)) {
  495. $ps_sort_field = 'lname,fname';
  496. }
  497. if($ps_sort_direction != 'desc') {
  498. $ps_sort_direction = 'asc';
  499. }
  500. $va_query_params = array();
  501. $vs_user_class_sql = '';
  502. if (is_array($pa_userclass) && sizeof($pa_userclass)) {
  503. $vs_user_class_sql = " WHERE userclass IN (?)";
  504. $va_query_params[] = $pa_userclass;
  505. }
  506. if ($ps_sort_field == 'last_login') {
  507. $vs_sort = '';
  508. } else {
  509. $vs_sort = "ORDER BY {$ps_sort_field} {$ps_sort_direction}";
  510. }
  511. $qr_users = $o_db->query("
  512. SELECT *
  513. FROM ca_users
  514. {$vs_user_class_sql}
  515. {$vs_sort}
  516. ", $va_query_params);
  517. $va_users = array();
  518. while($qr_users->nextRow()) {
  519. if (!is_array($va_vars = $qr_users->getVars('vars'))) { $va_vars = array(); }
  520. if (is_array($va_volatile_vars = $qr_users->getVars('volatile_vars'))) {
  521. $va_vars = array_merge($va_vars, $va_volatile_vars);
  522. }
  523. $va_users[$qr_users->get('user_id')] = array_merge($qr_users->getRow(), array('last_login' => $va_vars['last_login']));
  524. }
  525. return $va_users;
  526. }
  527. # ----------------------------------------
  528. /**
  529. * Returns HTML multiple <select> with list of "full" users
  530. *
  531. * @param array $pa_options (optional) array of options. Keys are:
  532. * size = height of multiple select, in rows; default is 8
  533. * name = HTML form element name to apply to role <select>; default is 'groups'
  534. * id = DOM id to apply to role <select>; default is no id
  535. * label = String to label form element with
  536. * selected = User_id values to select
  537. * @return string Returns HTML containing form element and form label
  538. */
  539. public function userListAsHTMLFormElement($pa_options=null) {
  540. $vn_size = (isset($pa_options['size']) && ($pa_options['size'] > 0)) ? $pa_options['size'] : 8;
  541. $vs_name = (isset($pa_options['name'])) ? $pa_options['name'] : 'users';
  542. $vs_id = (isset($pa_options['id'])) ? $pa_options['id'] : '';
  543. $vs_label = (isset($pa_options['label'])) ? $pa_options['label'] : _t('Users');
  544. $va_selected = (isset($pa_options['selected']) && is_array($pa_options['selected'])) ? $pa_options['selected'] : array();
  545. $va_users = $this->getUserList($pa_options);
  546. $vs_buf = '';
  547. if (sizeof($va_users)) {
  548. $vs_buf .= "<select multiple='1' name='{$vs_name}[]' size='{$vn_size}' id='{$vs_id}'>\n";
  549. foreach($va_users as $vn_user_id => $va_user_info) {
  550. $SELECTED = (in_array($vn_user_id, $va_selected)) ? "SELECTED='1'" : "";
  551. $vs_buf .= "<option value='{$vn_user_id}' {$SELECTED}>".$va_user_info['fname'].' '.$va_user_info['lname'].($va_user_info['email'] ? " (".$va_user_info['email'].")" : "")."</option>\n";
  552. }
  553. $vs_buf .= "</select>\n";
  554. }
  555. if ($vs_buf && ($vs_format = $this->_CONFIG->get('form_element_display_format'))) {
  556. $vs_format = str_replace("^ELEMENT", $vs_buf, $vs_format);
  557. $vs_format = str_replace("^LABEL", $vs_label, $vs_format);
  558. $vs_format = str_replace("^ERRORS", '', $vs_format);
  559. $vs_buf = str_replace("^EXTRA", '', $vs_format);
  560. }
  561. return $vs_buf;
  562. }
  563. # ----------------------------------------
  564. # --- Roles
  565. # ----------------------------------------
  566. /**
  567. * Add roles to current user.
  568. *
  569. * @access public
  570. * @param mixed $pm_roles Single role or list (array) of roles to add. Roles may be specified by name, code or id.
  571. * @return integer Returns number of roles added or false if there was an error. The number of roles added will not necessarily match the number of roles you tried to add. If you try to add the same role twice, or to add a role that already exists for this user, addRoles() will silently ignore it.
  572. */
  573. public function addRoles($pm_roles) {
  574. if (!is_array($pm_roles)) {
  575. $pm_roles = array($pm_roles);
  576. }
  577. if ($pn_user_id = $this->getPrimaryKey()) {
  578. $t_role = new ca_user_roles();
  579. $vn_roles_added = 0;
  580. foreach ($pm_roles as $vs_role) {
  581. $vb_got_role = 0;
  582. if (is_numeric($vs_role)) {
  583. $vb_got_role = $t_role->load($vs_role);
  584. }
  585. if (!$vb_got_role) {
  586. if (!$t_role->load(array("name" => $vs_role))) {
  587. if (!$t_role->load(array("code" => $vs_role))) {
  588. continue;
  589. }
  590. }
  591. $vb_got_role = 1;
  592. }
  593. $o_db = $this->getDb();
  594. $o_db->query("
  595. INSERT INTO ca_users_x_roles
  596. (user_id, role_id)
  597. VALUES
  598. (?, ?)
  599. ", (int)$pn_user_id, (int)$t_role->getPrimaryKey());
  600. if ($o_db->numErrors() == 0) {
  601. $vn_roles_added++;
  602. } else {
  603. $this->postError(930, _t("Database error adding role '%1': %2", $vs_role, join(';', $o_db->getErrors())),"User->addRoles()");
  604. }
  605. }
  606. return $vn_roles_added;
  607. } else {
  608. return false;
  609. }
  610. }
  611. # ----------------------------------------
  612. /**
  613. * Remove roles from current user.
  614. *
  615. * @access public
  616. * @param mixed $pm_roles Single role or list (array) of roles to remove. Roles may be specified by name, code or id.
  617. * @return bool Returns true on success, false on error.
  618. */
  619. public function removeRoles($pm_roles) {
  620. if (!is_array($pm_roles)) {
  621. $pm_roles = array($pm_roles);
  622. }
  623. if ($pn_user_id = $this->getPrimaryKey()) {
  624. $t_role = new ca_user_roles();
  625. $vn_roles_added = 0;
  626. $va_role_ids = array();
  627. foreach ($pm_roles as $vs_role) {
  628. $vb_got_role = 0;
  629. if (is_numeric($vs_role)) {
  630. $vb_got_role = $t_role->load($vs_role);
  631. }
  632. if (!$vb_got_role) {
  633. if (!$t_role->load(array("name" => $vs_role))) {
  634. if (!$t_role->load(array("code" => $vs_role))) {
  635. continue;
  636. }
  637. }
  638. $vb_got_role = 1;
  639. }
  640. if ($vb_got_role) {
  641. $va_role_ids[] = intval($t_role->getPrimaryKey());
  642. }
  643. }
  644. if (sizeof($va_role_ids) > 0) {
  645. $o_db = $this->getDb();
  646. $o_db->query("
  647. DELETE FROM ca_users_x_roles
  648. WHERE
  649. (user_id = ?) AND (role_id IN (".join(", ", $va_role_ids)."))
  650. ", (int)$pn_user_id);
  651. if ($o_db->numErrors()) {
  652. $this->postError(931, _t("Database error: %1", join(';', $o_db->getErrors())),"User->removeRoles()");
  653. return false;
  654. } else {
  655. return true;
  656. }
  657. } else {
  658. $this->postError(931, _t("No roles specified"),"User->removeRoles()");
  659. return false;
  660. }
  661. } else {
  662. return false;
  663. }
  664. }
  665. # ----------------------------------------
  666. /**
  667. * Removes all roles from current user.
  668. *
  669. * @access public
  670. * @return bool Returns true on success, false on error.
  671. */
  672. public function removeAllRoles() {
  673. if ($vn_user_id = $this->getPrimaryKey()) {
  674. $o_db = $this->getDb();
  675. $o_db->query("DELETE FROM ca_users_x_roles WHERE user_id = ?", (int)$vn_user_id);
  676. if ($o_db->numErrors()) {
  677. $this->postError(931, _t("Database error: %1", join(';', $o_db->getErrors())),"User->removeAllRoles()");
  678. return false;
  679. } else {
  680. return true;
  681. }
  682. } else {
  683. return false;
  684. }
  685. }
  686. # ----------------------------------------
  687. /**
  688. * Get list of all roles supported by the application. If you want to get the current user's roles, use getUserRoles()
  689. *
  690. * @access public
  691. * @return integer Returns associative array of roles. Key is role id, value is array containing information about the role.
  692. *
  693. * The role information array contains the following keys:
  694. * role_id (numeric id you can use in addRoles(), deleteRoles(), hasRole(), etc.)
  695. * name (the full name of the role)
  696. * code (a short code used for the role)
  697. * description (narrative description of role)
  698. */
  699. public function getRoleList() {
  700. $t_role = new ca_user_roles();
  701. return $t_role->getRoleList();
  702. }
  703. # ----------------------------------------
  704. /**
  705. * Get list of roles the current user has
  706. *
  707. * @access public
  708. * @return array Returns associative array of roles. Key is role id, value is array containing information about the role.
  709. *
  710. * The role information array contains the following keys:
  711. * role_id (numeric id you can use in addRoles(), deleteRoles(), hasRole(), etc.)
  712. * name (the full name of the role)
  713. * code (a short code used for the role)
  714. * description (narrative description of role)
  715. */
  716. public function getUserRoles() {
  717. if ($pn_user_id = $this->getPrimaryKey()) {
  718. $o_db = $this->getDb();
  719. $qr_res = $o_db->query("
  720. SELECT wur.role_id, wur.name, wur.code, wur.description, wur.rank
  721. FROM ca_user_roles wur
  722. INNER JOIN ca_users_x_roles AS wuxr ON wuxr.role_id = wur.role_id
  723. WHERE wuxr.user_id = ?
  724. ORDER BY wur.rank
  725. ", (int)$pn_user_id);
  726. $va_roles = array();
  727. while($qr_res->nextRow()) {
  728. $va_roles[$qr_res->get("role_id")] = $qr_res->getRow();
  729. }
  730. return $va_roles;
  731. } else {
  732. return false;
  733. }
  734. }
  735. # ----------------------------------------
  736. /**
  737. * Determines whether current user has a specified role.
  738. *
  739. * @access public
  740. * @param mixed $pm_role The role to test for the current user. Role may be specified by name, code or id.
  741. * @return bool Returns true if user has the role, false if not.
  742. */
  743. public function hasUserRole($ps_role) {
  744. if (!($pn_user_id = $this->getPrimaryKey())) {
  745. return false;
  746. }
  747. $vb_got_role = 0;
  748. $t_role = new ca_user_roles();
  749. if (is_numeric($ps_role)) {
  750. $vb_got_role = $t_role->load($ps_role);
  751. }
  752. if (!$vb_got_role) {
  753. if (!$t_role->load(array("name" => $ps_role))) {
  754. if (!$t_role->load(array("code" => $ps_role))) {
  755. return false;
  756. }
  757. }
  758. $vb_got_role = 1;
  759. }
  760. if ($vb_got_role) {
  761. $o_db = $this->getDb();
  762. $qr_res = $o_db->query("
  763. SELECT *
  764. FROM ca_users_x_roles
  765. WHERE
  766. (user_id = ?) AND
  767. (role_id = ?)
  768. ", (int)$pn_user_id, (int)$t_role->getPrimaryKey());
  769. if (!$qr_res) { return false; }
  770. if ($qr_res->nextRow()) {
  771. return true;
  772. } else {
  773. return false;
  774. }
  775. } else {
  776. $this->postError(940, _t("Invalid role '%1'", $ps_role),"User->hasRole()");
  777. return false;
  778. }
  779. }
  780. # ----------------------------------------
  781. /**
  782. * Determines whether current user has a specified role attached to their user record or
  783. * to an associated group.
  784. *
  785. * @access public
  786. * @param mixed $pm_role The role to test for the current user. Role may be specified by name, code or id.
  787. * @return bool Returns true if user has the role, false if not.
  788. */
  789. public function hasRole($ps_role) {
  790. if ($this->hasUserRole($ps_role)) {
  791. return true;
  792. } else {
  793. if ($this->hasGroupRole($ps_role)) {
  794. return true;
  795. }
  796. }
  797. return false;
  798. }
  799. # ----------------------------------------
  800. /**
  801. * Returns HTML multiple <select> with full list of roles for currently loaded user
  802. *
  803. * @param array $pa_options (optional) array of options. Keys are:
  804. * size = height of multiple select, in rows; default is 8
  805. * name = HTML form element name to apply to role <select>; default is 'roles'
  806. * id = DOM id to apply to role <select>; default is no id
  807. * label = String to label form element with
  808. * @return string Returns HTML containing form element and form label
  809. */
  810. public function roleListAsHTMLFormElement($pa_options=null) {
  811. $vn_size = (isset($pa_options['size']) && ($pa_options['size'] > 0)) ? $pa_options['size'] : 8;
  812. $vs_name = (isset($pa_options['name'])) ? $pa_options['name'] : 'roles';
  813. $vs_id = (isset($pa_options['id'])) ? $pa_options['id'] : '';
  814. $vs_label = (isset($pa_options['label'])) ? $pa_options['label'] : _t('Roles');
  815. $va_roles = $this->getRoleList();
  816. $vs_buf = '';
  817. if (sizeof($va_roles)) {
  818. if(!$va_user_roles = $this->getUserRoles()) { $va_user_roles = array(); }
  819. $vs_buf .= "<select multiple='1' name='{$vs_name}[]' size='{$vn_size}' id='{$vs_id}'>\n";
  820. foreach($va_roles as $vn_role_id => $va_role_info) {
  821. $SELECTED = (isset($va_user_roles[$vn_role_id]) && $va_user_roles[$vn_role_id]) ? "SELECTED='1'" : "";
  822. $vs_buf .= "<option value='{$vn_role_id}' {$SELECTED}>".$va_role_info['name']." [".$va_role_info["code"]."]</option>\n";
  823. }
  824. $vs_buf .= "</select>\n";
  825. }
  826. if ($vs_buf && ($vs_format = $this->_CONFIG->get('form_element_display_format'))) {
  827. $vs_format = str_replace("^ELEMENT", $vs_buf, $vs_format);
  828. $vs_format = str_replace("^LABEL", $vs_label, $vs_format);
  829. $vs_format = str_replace("^ERRORS", '', $vs_format);
  830. $vs_buf = str_replace("^EXTRA", '', $vs_format);
  831. }
  832. return $vs_buf;
  833. }
  834. # ----------------------------------------
  835. # --- Groups
  836. # ----------------------------------------
  837. /**
  838. * Add current user to one or more groups.
  839. *
  840. * @access public
  841. * @param mixed $pm_groups Single group or list (array) of group to add user to. Groups may be specified by name, short name or numeric id.
  842. * @return integer Returns number of groups user was added to or false if there was an error. The number of groups user was added to will not necessarily match the number of groups you passed in $pm_groups. If you try to add the user to the same group twice, or to a group that the user is already a member of, addToGroups() will silently ignore it.
  843. */
  844. public function addToGroups($pm_groups) {
  845. if (!is_array($pm_groups)) {
  846. $pm_groups = array($pm_groups);
  847. }
  848. if ($pn_user_id = $this->getPrimaryKey()) {
  849. $t_group = new ca_user_groups();
  850. $vn_groups_added = 0;
  851. foreach ($pm_groups as $vs_group) {
  852. $vb_got_group = 0;
  853. if (is_numeric($vs_group)) {
  854. $vb_got_group = $t_group->load($vs_group);
  855. }
  856. if (!$vb_got_group) {
  857. if (!$t_group->load(array("name" => $vs_group))) {
  858. if (!$t_group->load(array("code" => $vs_group))) {
  859. continue;
  860. }
  861. }
  862. $vb_got_group = 1;
  863. }
  864. $o_db = $this->getDb();
  865. $o_db->query("
  866. INSERT INTO ca_users_x_groups
  867. (user_id, group_id)
  868. VALUES
  869. (?, ?)
  870. ", (int)$pn_user_id, (int)$t_group->getPrimaryKey());
  871. if ($o_db->numErrors() == 0) {
  872. $vn_groups_added++;
  873. } else {
  874. $this->postError(935, _t("Database error: %1", join(';', $o_db->getErrors())),"User->addToGroups()");
  875. }
  876. }
  877. return $vn_groups_added;
  878. } else {
  879. return false;
  880. }
  881. }
  882. # ----------------------------------------
  883. /**
  884. * Remove current user from one or more groups.
  885. *
  886. * @access public
  887. * @param mixed $pm_groups Single group or list (array) of groups to remove current user from. Groups may be specified by name, short name or id.
  888. * @return bool Returns true on success, false on error.
  889. */
  890. public function removeFromGroups($pm_groups) {
  891. if (!is_array($pm_groups)) {
  892. $pm_groups = array($pm_groups);
  893. }
  894. if ($pn_user_id = $this->getPrimaryKey()) {
  895. $t_group = new ca_user_groups();
  896. $vn_groups_added = 0;
  897. $va_group_ids = array();
  898. foreach ($pm_groups as $ps_group) {
  899. $vb_got_group = 0;
  900. if (is_numeric($ps_group)) {
  901. $vb_got_group = $t_group->load($ps_group);
  902. }
  903. if (!$vb_got_group) {
  904. if (!$t_group->load(array("name" => $ps_group))) {
  905. if (!$t_group->load(array("name_short" => $ps_group))) {
  906. continue;
  907. }
  908. }
  909. $vb_got_group = 1;
  910. }
  911. if ($vb_got_group) {
  912. $va_group_ids[] = intval($t_group->getPrimaryKey());
  913. }
  914. }
  915. if (sizeof($va_group_ids) > 0) {
  916. $o_db = $this->getDb();
  917. $o_db->query("
  918. DELETE FROM ca_users_x_groups
  919. WHERE (user_id = ?) AND (group_id IN (".join(", ", $va_group_ids)."))
  920. ", (int)$pn_user_id);
  921. if ($o_db->numErrors()) {
  922. $this->postError(936, _t("Database error: %1", join(';', $o_db->getErrors())),"User->removeFromGroups()");
  923. return false;
  924. } else {
  925. return true;
  926. }
  927. } else {
  928. $this->postError(945, _t("No groups specified"),"User->removeFromGroups()");
  929. return false;
  930. }
  931. } else {
  932. return false;
  933. }
  934. }
  935. # ----------------------------------------
  936. /**
  937. * Remove current user from all associated groups.
  938. *
  939. * @access public
  940. * @return bool Returns true on success, false on error.
  941. */
  942. public function removeFromAllGroups() {
  943. if ($vn_user_id = $this->getPrimaryKey()) {
  944. $o_db = $this->getDb();
  945. $o_db->query("DELETE FROM ca_users_x_groups WHERE user_id = ?", (int)$vn_user_id);
  946. if ($o_db->numErrors()) {
  947. $this->postError(936, _t("Database error: %1", join(';', $o_db->getErrors())),"User->removeFromAllGroups()");
  948. return false;
  949. } else {
  950. return true;
  951. }
  952. } else {
  953. return false;
  954. }
  955. }
  956. # ----------------------------------------
  957. /**
  958. * Get list of all available user groups. If you want to get a list of the current user's groups, use getUserGroups()
  959. *
  960. * @access public
  961. * @return integer Returns associative array of groups. Key is group id, value is array containing information about the group.
  962. *
  963. * The group information array contains the following keys:
  964. * group_id (numeric id you can use in addRoles(), deleteRoles(), hasRole(), etc.)
  965. * name (the full name of the group)
  966. * name_short (an abbreviated name used for the group)
  967. * description (narrative description of group)
  968. * admin_id (user_id of group administrator)
  969. * admin_fname (first name of group administrator)
  970. * admin_lname (last name of group administrator)
  971. * admin_email (email address of group administrator)
  972. */
  973. public function getGroupList($pn_user_id=null) {
  974. $t_group = new ca_user_groups();
  975. return $t_group->getGroupList('name', 'asc', $pn_user_id);
  976. }
  977. # ----------------------------------------
  978. /**
  979. * Get list of roles the current user has via associated groups
  980. *
  981. * @access public
  982. * @return array Returns associative array of roles. Key is role id, value is array containing information about the role.
  983. *
  984. * The role information array contains the following keys:
  985. * role_id (numeric id you can use in addRoles(), deleteRoles(), hasRole(), etc.)
  986. * name (the full name of the role)
  987. * code (a short code used for the role)
  988. * description (narrative description of role)
  989. */
  990. public function getGroupRoles() {
  991. if ($pn_user_id = $this->getPrimaryKey()) {
  992. $o_db = $this->getDb();
  993. $qr_res = $o_db->query("
  994. SELECT wur.role_id, wur.name, wur.code, wur.description, wur.rank
  995. FROM ca_user_roles wur
  996. INNER JOIN ca_groups_x_roles AS wgxr ON wgxr.role_id = wur.role_id
  997. INNER JOIN ca_users_x_groups AS wuxg ON wuxg.group_id = wgxr.group_id
  998. WHERE wuxg.user_id = ?
  999. ORDER BY wur.rank
  1000. ", (int)$pn_user_id);
  1001. $va_roles = array();
  1002. while($qr_res->nextRow()) {
  1003. $va_roles[$qr_res->get("role_id")] = $qr_res->getRow();
  1004. }
  1005. return $va_roles;
  1006. } else {
  1007. return false;
  1008. }
  1009. }
  1010. # ----------------------------------------
  1011. /**
  1012. * Determines whether current user is in a group with the specified role.
  1013. *
  1014. * @access public
  1015. * @param mixed $pm_role The role to test for the current user. Role may be specified by name, code or id.
  1016. * @return bool Returns true if user has the role, false if not.
  1017. */
  1018. public function hasGroupRole($ps_role) {
  1019. if (!($pn_user_id = $this->getPrimaryKey())) {
  1020. return false;
  1021. }
  1022. $vb_got_role = 0;
  1023. $t_role = new ca_user_roles();
  1024. if (is_numeric($ps_role)) {
  1025. $vb_got_role = $t_role->load($ps_role);
  1026. }
  1027. if (!$vb_got_role) {
  1028. if (!$t_role->load(array("name" => $ps_role))) {
  1029. if (!$t_role->load(array("code" => $ps_role))) {
  1030. return false;
  1031. }
  1032. }
  1033. $vb_got_role = 1;
  1034. }
  1035. if ($vb_got_role) {
  1036. $o_db = $this->getDb();
  1037. $qr_res = $o_db->query("
  1038. SELECT wgr.role_id
  1039. FROM ca_groups_x_roles wgr
  1040. INNER JOIN ca_users_x_groups AS wuxg ON wuxg.group_id = wgr.group_id
  1041. WHERE
  1042. (wuxg.user_id = ?) AND
  1043. (wgr.role_id = ?)
  1044. ", (int)$pn_user_id, (int)$t_role->getPrimaryKey());
  1045. if ($qr_res->nextRow()) {
  1046. return true;
  1047. } else {
  1048. return false;
  1049. }
  1050. } else {
  1051. $this->postError(940, _t("Invalid role '%1'", $ps_role),"User->hasGroupRole()");
  1052. return false;
  1053. }
  1054. }
  1055. # ----------------------------------------
  1056. /**
  1057. * Get list of current user's groups.
  1058. *
  1059. * @access public
  1060. * @return array Returns associative array of groups. Key is group id, value is array containing information about the group.
  1061. *
  1062. * The group information array contains the following keys:
  1063. * group_id (numeric id you can use in addRoles(), deleteRoles(), hasRole(), etc.)
  1064. * name (the full name of the group)
  1065. * name_short (an abbreviated name used for the group)
  1066. * description (narrative description of group)
  1067. * admin_id (user_id of group administrator)
  1068. * admin_fname (first name of group administrator)
  1069. * admin_lname (last name of group administrator)
  1070. * admin_email (email address of group administrator)
  1071. */
  1072. public function getUserGroups() {
  1073. if ($pn_user_id = $this->getPrimaryKey()) {
  1074. $o_db = $this->getDb();
  1075. $qr_res = $o_db->query("
  1076. SELECT
  1077. wug.group_id, wug.name, wug.code, wug.description,
  1078. wug.user_id admin_id, wu.fname admin_fname, wu.lname admin_lname, wu.email admin_email
  1079. FROM ca_user_groups wug
  1080. LEFT JOIN ca_users AS wu ON wug.user_id = wu.user_id
  1081. INNER JOIN ca_users_x_groups AS wuxg ON wuxg.group_id = wug.group_id
  1082. WHERE wuxg.user_id = ?
  1083. ORDER BY wug.rank
  1084. ", (int)$pn_user_id);
  1085. $va_groups = array();
  1086. while($qr_res->nextRow()) {
  1087. $va_groups[$qr_res->get("group_id")] = $qr_res->getRow();
  1088. }
  1089. return $va_groups;
  1090. } else {
  1091. return false;
  1092. }
  1093. }
  1094. # ----------------------------------------
  1095. /**
  1096. * Determines whether current user is a member of the specified group.
  1097. *
  1098. * @access public
  1099. * @param mixed $ps_group The group to test for the current user for membership in. Group may be specified by name, short name or id.
  1100. * @return bool Returns true if user is a member of the group, false if not.
  1101. */
  1102. public function inGroup($ps_group) {
  1103. if (!($pn_user_id = $this->getPrimaryKey())) {
  1104. return false;
  1105. }
  1106. $vb_got_group = 0;
  1107. $t_group = new ca_user_groups();
  1108. if (is_numeric($ps_group)) {
  1109. $vb_got_group = $t_group->load($ps_group);
  1110. }
  1111. if (!$vb_got_group) {
  1112. if (!$t_group->load(array("name" => $ps_group))) {
  1113. if (!$t_group->load(array("name_short" => $ps_group))) {
  1114. return false;
  1115. }
  1116. }
  1117. $vb_got_group = 1;
  1118. }
  1119. if ($vb_got_group) {
  1120. $o_db = $this->getDb();
  1121. $qr_res = $o_db->query("
  1122. SELECT link_id
  1123. FROM ca_users_x_groups
  1124. WHERE
  1125. (user_id = ?) AND
  1126. (group_id = ?)
  1127. ", (int)$pn_user_id, (int)$t_group->getPrimaryKey());
  1128. if ($qr_res->nextRow()) {
  1129. return true;
  1130. } else {
  1131. return false;
  1132. }
  1133. } else {
  1134. $this->postError(945, _t("Group '%1' does not exist", $ps_group),"User->inGroup()");
  1135. return false;
  1136. }
  1137. }
  1138. # ----------------------------------------
  1139. /**
  1140. * Returns HTML multiple <select> with full list of groups for currently loaded user
  1141. *
  1142. * @param array $pa_options (optional) array of options. Keys are:
  1143. * size = height of multiple select, in rows; default is 8
  1144. * name = HTML form element name to apply to role <select>; default is 'groups'
  1145. * id = DOM id to apply to role <select>; default is no id
  1146. * label = String to label form element with
  1147. * @return string Returns HTML containing form element and form label
  1148. */
  1149. public function groupListAsHTMLFormElement($pa_options=null) {
  1150. $vn_size = (isset($pa_options['size']) && ($pa_options['size'] > 0)) ? $pa_options['size'] : 8;
  1151. $vs_name = (isset($pa_options['name'])) ? $pa_options['name'] : 'groups';
  1152. $vs_id = (isset($pa_options['id'])) ? $pa_options['id'] : '';
  1153. $vs_label = (isset($pa_options['label'])) ? $pa_options['label'] : _t('Groups');
  1154. $va_groups = $this->getGroupList();
  1155. $vs_buf = '';
  1156. if (sizeof($va_groups)) {
  1157. if(!$va_user_groups = $this->getUserGroups()) { $va_user_groups = array(); }
  1158. $vs_buf .= "<select multiple='1' name='{$vs_name}[]' size='{$vn_size}' id='{$vs_id}'>\n";
  1159. foreach($va_groups as $vn_group_id => $va_group_info) {
  1160. $SELECTED = (isset($va_user_groups[$vn_group_id]) && $va_user_groups[$vn_group_id]) ? "SELECTED='1'" : "";
  1161. $vs_buf .= "<option value='{$vn_group_id}' {$SELECTED}>".$va_group_info['name']." [".$va_group_info["code"]."]</option>\n";
  1162. }
  1163. $vs_buf .= "</select>\n";
  1164. }
  1165. if ($vs_buf && ($vs_format = $this->_CONFIG->get('form_element_display_format'))) {
  1166. $vs_format = str_replace("^ELEMENT", $vs_buf, $vs_format);
  1167. $vs_format = str_replace("^LABEL", $vs_label, $vs_format);
  1168. $vs_format = str_replace("^ERRORS", '', $vs_format);
  1169. $vs_buf = str_replace("^EXTRA", '', $vs_format);
  1170. }
  1171. return $vs_buf;
  1172. }
  1173. # ----------------------------------------
  1174. # --- User preferences
  1175. # ----------------------------------------
  1176. /**
  1177. * Returns value of user preference. Returns null if preference does not exist.
  1178. *
  1179. * @access public
  1180. * @param string $ps_pref Name of user preference
  1181. * @return mixed Value of variable (string, number or array); null is variable is not defined.
  1182. */
  1183. public function getPreference($ps_pref) {
  1184. if ($this->isValidPreference($ps_pref)) {
  1185. $va_prefs = $this->getVar("_user_preferences");
  1186. $va_pref_info = $this->getPreferenceInfo($ps_pref);
  1187. if (!isset($va_prefs)) {
  1188. return isset($va_pref_info["default"]) ? $va_pref_info["default"] : null;
  1189. }
  1190. return isset($va_prefs[$ps_pref]) ? $va_prefs[$ps_pref] : ($va_pref_info["default"] ? $va_pref_info["default"] : null);
  1191. } else {
  1192. $this->postError(920, _t("%1 is not a valid user preference", $ps_pref),"User->getPreference()");
  1193. return null;
  1194. }
  1195. }
  1196. # ----------------------------------------
  1197. /**
  1198. * Sets value of user preference. Returns false if preference or value is invalid.
  1199. *
  1200. * @access public
  1201. * @param string $ps_pref Name of user preference
  1202. * @param mixed $ps_val Value of preference
  1203. * @return bool True if preference was set; false if it could not be set.
  1204. */
  1205. public function setPreference($ps_pref, $ps_val) {
  1206. if ($this->isValidPreference($ps_pref)) {
  1207. if ($this->isValidPreferenceValue($ps_pref, $ps_val, 1)) {
  1208. $va_prefs = $this->getVar("_user_preferences");
  1209. $va_prefs[$ps_pref] = $ps_val;
  1210. $this->setVar("_user_preferences", $va_prefs);
  1211. return true;
  1212. } else {
  1213. return false;
  1214. }
  1215. } else {
  1216. $this->postError(920, _t("%1 is not a valid user preference", $ps_pref),"User->getPreference()");
  1217. return false;
  1218. }
  1219. }
  1220. # ----------------------------------------
  1221. /**
  1222. * Returns list of supported preference names. If the $ps_group_name is provided, then only
  1223. * preference names for the specified group are returned. Otherwise all supported preference
  1224. * names are returned.
  1225. *
  1226. * @access public
  1227. * @param string $ps_group_name Name of user preference group
  1228. * @return array List of valid preferences
  1229. */
  1230. public function getValidPreferences($ps_group_name="") {
  1231. if ($ps_group_name) {
  1232. if ($va_group = $this->getPreferenceGroupInfo($ps_group_name)) {
  1233. return array_keys($va_group["preferences"]);
  1234. } else {
  1235. return array();
  1236. }
  1237. } else {
  1238. $this->loadUserPrefDefs();
  1239. return array_keys($this->_user_pref_defs->getAssoc("preferenceDefinitions"));
  1240. }
  1241. }
  1242. # ----------------------------------------
  1243. /**
  1244. * Returns list of supported preference group names. Preference groups are simply
  1245. * groupings of related preference values. Typically preference groups are
  1246. * used by preference configuration user interfaces to group related preferences
  1247. * together in convenient units. When using preferences to in application code it
  1248. * is not usually important what group a preference belongs to.
  1249. *
  1250. * @access public
  1251. * @return array List of supported preference group names
  1252. */
  1253. public function getValidPreferenceGroups() {
  1254. $this->loadUserPrefDefs();
  1255. return array_keys($this->_user_pref_defs->getAssoc("preferenceGroups"));
  1256. }
  1257. # ----------------------------------------
  1258. /**
  1259. * Tests whether a preference name is supported or not.
  1260. *
  1261. * @access public
  1262. * @param string $ps_pref Name of user preference
  1263. * @return bool Returns true if preference is supports; false if it is not supported.
  1264. */
  1265. public function isValidPreference($ps_pref) {
  1266. return (in_array($ps_pref, $this->getValidPreferences())) ? true : false;
  1267. }
  1268. # ----------------------------------------
  1269. /**
  1270. * Tests whether a value is valid for a given preference
  1271. *
  1272. * @access public
  1273. * @param string $ps_pref Name of user preference
  1274. * @param mixed $ps_value Preference value to test
  1275. * @param bool $pb_post_errors If true, invalid parameter causes errors to be thrown; if false, error messages are supressed. Default is false.
  1276. * @return bool Returns true if value is valid; false if value is invalid.
  1277. */
  1278. public function isValidPreferenceValue($ps_pref, $ps_value, $pb_post_errors=false) {
  1279. if ($this->isValidPreference($ps_pref)) {
  1280. $va_pref_info = $this->getPreferenceInfo($ps_pref);
  1281. # check number of picks for checkboxes
  1282. if (is_array($ps_value) && isset($va_pref_info["picks"])) {
  1283. if (!((sizeof($ps_value) >= $va_pref_info["picks"]["minimum"]) && (sizeof($ps_value) <= $va_pref_info["picks"]["maximum"]))) {
  1284. if ($pb_post_errors) {
  1285. if ($va_pre

Large files files are truncated, but you can click here to view the full file