PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/functions/tlUser.class.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 987 lines | 583 code | 111 blank | 293 comment | 74 complexity | b1736ec39ea45d6b369ddd48a33d94ef MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * TestLink Open Source Project - http://testlink.sourceforge.net/
  4. * This script is distributed under the GNU General Public License 2 or later.
  5. *
  6. * @package TestLink
  7. * @copyright 2007-2009, TestLink community
  8. * @version CVS: $Id: tlUser.class.php,v 1.11 2010/07/04 16:33:39 franciscom Exp $
  9. * @filesource http://testlink.cvs.sourceforge.net/viewvc/testlink/testlink/lib/functions/user.class.php?view=markup
  10. * @link http://www.teamst.org/index.php
  11. *
  12. * @internal Revisions:
  13. *
  14. * 20100704 - franciscom - getAccessibleTestPlans() - BUGID 3526
  15. * 20100522 - franciscom - getAccessibleTestPlans() - added arguments options
  16. * 20100427 - franciscom - BUGID 3396 - writePasswordToDB() method
  17. * 20100326 - franciscom - setActive() method
  18. * 20100217 - franciscom - getNamesForProjectRight() - fixed error displayed on event viewer + refactoring
  19. * 20090726 - franciscom - new method getAccessibleTestPlans()
  20. * 20090419 - franciscom - refactoring replace product with test project (where possible).
  21. * 20090101 - franciscom - changes to deleteFromDB() due to Foreing Key constraints
  22. * 20081213 - franciscom - removed global coupling to access config parameters
  23. */
  24. /**
  25. * Class for handling users in TestLink
  26. *
  27. * @package TestLink
  28. * @author Andreas Morsing
  29. * @uses config.inc.php
  30. * @since 1.7
  31. */
  32. class tlUser extends tlDBObject
  33. {
  34. /**
  35. * @var the name of the table the object is stored into
  36. * @access private
  37. */
  38. private $object_table = "users";
  39. /**
  40. * @var string the first name of the user
  41. */
  42. public $firstName;
  43. /**
  44. * @var string the last name of the user
  45. */
  46. public $lastName;
  47. /**
  48. * @var string the email address of the user
  49. */
  50. public $emailAddress;
  51. /**
  52. * @var string the locale of the user (eG de_DE, en_GB)
  53. */
  54. public $locale;
  55. /**
  56. * @var boolean true if the user is active, false else
  57. */
  58. public $isActive;
  59. /**
  60. * @var integer the default testprojectID of the user
  61. */
  62. public $defaultTestprojectID;
  63. /**
  64. * @var tlRole the global role of the user
  65. */
  66. public $globalRole;
  67. /**
  68. * @var integer the id of global role of the user
  69. */
  70. public $globalRoleID;
  71. /**
  72. * @var array of tlRole, holds the roles of the user for the different testprojects
  73. */
  74. public $tprojectRoles;
  75. /**
  76. * @var array of tlRole, holds the roles of the user for the different testplans
  77. */
  78. public $tplanRoles;
  79. /**
  80. * @var string the login of the user
  81. */
  82. public $login;
  83. /**
  84. * @var string the API Key for the user
  85. */
  86. public $userApiKey;
  87. /**
  88. * @var string the password of the user
  89. * @access protected
  90. */
  91. protected $password;
  92. /** configuration options */
  93. //@TODO should be moved inside a tlConfig class
  94. protected $usernameFormat;
  95. protected $loginMethod;
  96. protected $maxLoginLength;
  97. /** error codes */
  98. const E_LOGINLENGTH = -1;
  99. const E_EMAILLENGTH = -2;
  100. const E_NOTALLOWED = -4;
  101. const E_DBERROR = -8;
  102. const E_FIRSTNAMELENGTH = -16;
  103. const E_LASTNAMELENGTH = -32;
  104. const E_PWDEMPTY = -64;
  105. const E_PWDDONTMATCH = -128;
  106. const E_LOGINALREADYEXISTS = -256;
  107. const E_EMAILFORMAT = -512;
  108. const S_PWDMGTEXTERNAL = 2;
  109. //search options
  110. const USER_O_SEARCH_BYLOGIN = 2;
  111. //detail leveles
  112. const TLOBJ_O_GET_DETAIL_ROLES = 1;
  113. const SKIP_CHECK_AT_TESTPROJECT_LEVEL = -1;
  114. const SKIP_CHECK_AT_TESTPLAN_LEVEL = -1;
  115. /**
  116. * Constructor, creates the user object
  117. *
  118. * @param resource $db database handler
  119. */
  120. function __construct($dbID = null)
  121. {
  122. parent::__construct($dbID);
  123. $this->object_table = $this->tables['users'];
  124. $authCfg = config_get('authentication');
  125. $this->usernameFormat = config_get('username_format');
  126. $this->loginRegExp = config_get('validation_cfg')->user_login_valid_regex;
  127. $this->maxLoginLength = 30;
  128. $this->loginMethod = $authCfg['method'];
  129. $this->globalRoleID = config_get('default_roleid');
  130. $this->locale = config_get('default_language');
  131. $this->isActive = 1;
  132. $this->tprojectRoles = null;
  133. $this->tplanRoles = null;
  134. }
  135. /**
  136. * Cleans the object by resetting the members to default values
  137. *
  138. * @param mixed $options tlUser/tlObject options
  139. */
  140. protected function _clean($options = self::TLOBJ_O_SEARCH_BY_ID)
  141. {
  142. $this->firstName = null;
  143. $this->lastName = null;
  144. $this->emailAddress = null;
  145. $this->locale = null;
  146. $this->password = null;
  147. $this->isActive = null;
  148. $this->defaultTestprojectID = null;
  149. $this->globalRoleID = null;
  150. $this->tprojectRoles = null;
  151. $this->tplanRoles = null;
  152. $this->userApiKey = null;
  153. if (!($options & self::TLOBJ_O_SEARCH_BY_ID))
  154. {
  155. $this->dbID = null;
  156. }
  157. if (!($options & self::USER_O_SEARCH_BYLOGIN))
  158. {
  159. $this->login = null;
  160. }
  161. }
  162. /**
  163. * Checks if password management is external (like LDAP)...
  164. *
  165. * @return boolean return true if password management is external, else false
  166. * @TODO schlundus, should be moved inside a super tl configuration class
  167. */
  168. static public function isPasswordMgtExternal()
  169. {
  170. $authCfg = config_get('authentication');
  171. return ($authCfg['method'] != '' && $authCfg['method'] != 'MD5') ? true : false;
  172. }
  173. /**
  174. * Obtain a secure password.
  175. * You can choose the number of alphanumeric characters to add and
  176. * the number of non-alphanumeric characters.
  177. * You can add another characters to the non-alphanumeric list if you need.
  178. *
  179. * @param integer $numAlpha number alphanumeric characters in generated password
  180. * @param integer $numNonAlpha number special characters in generated password
  181. *
  182. * @return string the generated password
  183. */
  184. static public function generatePassword($numAlpha = 6,$numNonAlpha = 2)
  185. {
  186. $listAlpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  187. $listNonAlpha = ',;:!?.$/*-+&@_+;./*&?$-!,';
  188. return str_shuffle(substr(str_shuffle($listAlpha),0,$numAlpha) .
  189. substr(str_shuffle($listNonAlpha),0,$numNonAlpha));
  190. }
  191. /**
  192. * not used at the moment, only placeholder
  193. *
  194. * @return void
  195. * @TODO implement
  196. **/
  197. function create()
  198. {
  199. }
  200. //----- BEGIN interface iDBSerialization -----
  201. /**
  202. * Reads an user object identified by its database id from the given database
  203. *
  204. * @param resource &$db reference to database handler
  205. * @param mixed $options (optional) tlUser/tlObject options
  206. *
  207. * @return integer tl::OK if the object could be read from the db, else tl::ERROR
  208. */
  209. public function readFromDB(&$db,$options = self::TLOBJ_O_SEARCH_BY_ID)
  210. {
  211. $this->_clean($options);
  212. $sql = "SELECT id,login,password,first,last,email,role_id,locale, " .
  213. " login AS fullname, active,default_testproject_id, script_key " .
  214. " FROM {$this->object_table}";
  215. $clauses = null;
  216. if ($options & self::TLOBJ_O_SEARCH_BY_ID)
  217. {
  218. $clauses[] = "id = {$this->dbID}";
  219. }
  220. if ($options & self::USER_O_SEARCH_BYLOGIN)
  221. {
  222. $clauses[] = "login = '".$db->prepare_string($this->login)."'";
  223. }
  224. if ($clauses)
  225. {
  226. $sql .= " WHERE " . implode(" AND ",$clauses);
  227. }
  228. $info = $db->fetchFirstRow($sql);
  229. if ($info)
  230. {
  231. $this->dbID = $info['id'];
  232. $this->firstName = $info['first'];
  233. $this->lastName = $info['last'];
  234. $this->login = $info['login'];
  235. $this->emailAddress = $info['email'];
  236. $this->globalRoleID = $info['role_id'];
  237. $this->userApiKey = $info['script_key'];
  238. if ($this->globalRoleID)
  239. {
  240. $this->globalRole = new tlRole($this->globalRoleID);
  241. $this->globalRole->readFromDB($db);
  242. }
  243. if ($this->detailLevel & self::TLOBJ_O_GET_DETAIL_ROLES)
  244. {
  245. $this->readTestProjectRoles($db);
  246. $this->readTestPlanRoles($db);
  247. }
  248. $this->locale = $info['locale'];
  249. $this->password = $info['password'];
  250. $this->isActive = $info['active'];
  251. $this->defaultTestprojectID = $info['default_testproject_id'];
  252. }
  253. return $info ? tl::OK : tl::ERROR;
  254. }
  255. /**
  256. * Fetches all the testproject roles of of the user, and store them into the object.
  257. * Result could be limited to a certain testproject
  258. *
  259. * @param resource &$db reference to database handler
  260. * @param integer $testProjectID Identifier of the testproject to read the roles for,
  261. * if null all roles are read
  262. *
  263. * @return integer returns tl::OK
  264. */
  265. public function readTestProjectRoles(&$db,$testProjectID = null)
  266. {
  267. $sql = "SELECT testproject_id,role_id " .
  268. " FROM {$this->tables['user_testproject_roles']} user_testproject_roles " .
  269. " WHERE user_id = {$this->dbID}";
  270. if ($testProjectID)
  271. {
  272. $sql .= " AND testproject_id = {$testProjectID}";
  273. }
  274. $allRoles = $db->fetchColumnsIntoMap($sql,'testproject_id','role_id');
  275. $this->tprojectRoles = null;
  276. if (sizeof($allRoles))
  277. {
  278. $roleCache = null;
  279. foreach($allRoles as $tprojectID => $roleID)
  280. {
  281. if (!isset($roleCache[$roleID]))
  282. {
  283. $tprojectRole = tlRole::createObjectFromDB($db,$roleID,"tlRole",true);
  284. $roleCache[$roleID] = $tprojectRole;
  285. }
  286. else
  287. {
  288. $tprojectRole = clone($roleCache[$roleID]);
  289. }
  290. if ($tprojectRole)
  291. {
  292. $this->tprojectRoles[$tprojectID] = $tprojectRole;
  293. }
  294. }
  295. }
  296. return tl::OK;
  297. }
  298. /**
  299. * Fetches all the testplan roles of of the user, and store them into the object.
  300. * Result could be limited to a certain testplan
  301. *
  302. * @param resource &$db reference to database handler
  303. * @param integer $testPlanID Identifier of the testplan to read the roles for, if null all roles are read
  304. *
  305. * @return integer returns tl::OK
  306. */
  307. public function readTestPlanRoles(&$db,$testPlanID = null)
  308. {
  309. $sql = "SELECT testplan_id,role_id " .
  310. " FROM {$this->tables['user_testplan_roles']} user_testplan_roles " .
  311. " WHERE user_id = {$this->dbID}";
  312. if ($testPlanID)
  313. {
  314. $sql .= " AND testplan_id = {$testPlanID}";
  315. }
  316. $allRoles = $db->fetchColumnsIntoMap($sql,'testplan_id','role_id');
  317. $this->tplanRoles = null;
  318. if (sizeof($allRoles))
  319. {
  320. $roleCache = null;
  321. foreach($allRoles as $tplanID => $roleID)
  322. {
  323. if (!isset($roleCache[$roleID]))
  324. {
  325. $tplanRole = tlRole::createObjectFromDB($db,$roleID,"tlRole",true);
  326. $roleCache[$roleID] = $tplanRole;
  327. }
  328. else
  329. {
  330. $tplanRole = clone($roleCache[$roleID]);
  331. }
  332. if ($tplanRole)
  333. {
  334. $this->tplanRoles[$tplanID] = $tplanRole;
  335. }
  336. }
  337. }
  338. return tl::OK;
  339. }
  340. /**
  341. * Writes the object into the database
  342. *
  343. * @param resource &$db reference to database handler
  344. * @return integer tl::OK if the object could be written to the db, else error code
  345. */
  346. public function writeToDB(&$db)
  347. {
  348. $result = $this->checkDetails($db);
  349. if ($result >= tl::OK)
  350. {
  351. if($this->dbID)
  352. {
  353. $sql = "UPDATE {$this->tables['users']} " .
  354. "SET first = '" . $db->prepare_string($this->firstName) . "'" .
  355. ", last = '" . $db->prepare_string($this->lastName) . "'" .
  356. ", email = '" . $db->prepare_string($this->emailAddress) . "'" .
  357. ", locale = ". "'" . $db->prepare_string($this->locale) . "'" .
  358. ", password = ". "'" . $db->prepare_string($this->password) . "'" .
  359. ", role_id = ". $db->prepare_string($this->globalRoleID) .
  360. ", active = ". $db->prepare_string($this->isActive);
  361. $sql .= " WHERE id = " . $this->dbID;
  362. $result = $db->exec_query($sql);
  363. }
  364. else
  365. {
  366. $sql = "INSERT INTO {$this->tables['users']} (login,password,first,last,email,role_id,locale,active)
  367. VALUES ('" .
  368. $db->prepare_string($this->login) . "','" . $db->prepare_string($this->password) . "','" .
  369. $db->prepare_string($this->firstName) . "','" . $db->prepare_string($this->lastName) . "','" .
  370. $db->prepare_string($this->emailAddress) . "'," . $this->globalRoleID. ",'".
  371. $db->prepare_string($this->locale). "'," . $this->isActive . ")";
  372. $result = $db->exec_query($sql);
  373. if($result)
  374. {
  375. $this->dbID = $db->insert_id($this->tables['users']);
  376. }
  377. }
  378. $result = $result ? tl::OK : self::E_DBERROR;
  379. }
  380. return $result;
  381. }
  382. /**
  383. * WARNING: DO NOT USE THE FUNCTION - CAUSES DB INCONSISTENCE!
  384. *
  385. * @deprecated 1.8.3
  386. * @see #2407
  387. **/
  388. public function deleteFromDB(&$db)
  389. {
  390. $sqlSet = array();
  391. $sqlSet[] = "DELETE FROM {$this->table['user_assignments']} WHERE user_id = {$this->dbID}";
  392. $sqlSet[] = "DELETE FROM {$this->table['users']} WHERE id = {$this->dbID}";
  393. foreach($sqlSet as $sql)
  394. {
  395. $result = $db->exec_query($sql) ? tl::OK : tl::ERROR;
  396. if($result == tl::ERROR)
  397. {
  398. break;
  399. }
  400. }
  401. if ($result == tl::OK)
  402. {
  403. $result = $this->deleteTestProjectRoles($db);
  404. }
  405. return $result;
  406. }
  407. /**
  408. * Deletes all testproject related role assignments for a given user
  409. *
  410. * @param resource &$db reference to database handler
  411. * @param integer $userID the user ID
  412. *
  413. * @return integer tl::OK on success, tl:ERROR else
  414. **/
  415. protected function deleteTestProjectRoles(&$db)
  416. {
  417. $sql = "DELETE FROM {$this->tables['user_testproject_roles']} WHERE user_id = {$this->dbID}";
  418. return $db->exec_query($sql) ? tl::OK : tl::ERROR;
  419. }
  420. /**
  421. * Returns a user friendly representation of the user name
  422. *
  423. * @return string the display nmae
  424. */
  425. public function getDisplayName()
  426. {
  427. $keys = array('%first%','%last%','%login%','%email%');
  428. $values = array($this->firstName, $this->lastName,$this->login,$this->emailAddress);
  429. $displayName = trim(str_replace($keys,$values,$this->usernameFormat));
  430. return $displayName;
  431. }
  432. /**
  433. * Encrypts a given password with MD5
  434. *
  435. * @param $pwd the password to encrypt
  436. * @return string the encrypted password
  437. */
  438. protected function encryptPassword($pwd)
  439. {
  440. if (self::isPasswordMgtExternal())
  441. return self::S_PWDMGTEXTERNAL;
  442. return md5($pwd);
  443. }
  444. /**
  445. * Set encrypted password
  446. *
  447. * @param string $pwd the new password
  448. * @return integer return tl::OK is the password is stored, else errorcode
  449. */
  450. public function setPassword($pwd)
  451. {
  452. if (self::isPasswordMgtExternal())
  453. {
  454. return self::S_PWDMGTEXTERNAL;
  455. }
  456. $pwd = trim($pwd);
  457. if ($pwd == "")
  458. {
  459. return self::E_PWDEMPTY;
  460. }
  461. $this->password = $this->encryptPassword($pwd);
  462. return tl::OK;
  463. }
  464. /**
  465. * Getter for the password of the user
  466. *
  467. * @return string the password of the user
  468. */
  469. public function getPassword()
  470. {
  471. return $this->password;
  472. }
  473. /**
  474. * compares a given password with the current password of the user
  475. *
  476. * @param string $pwd the password to compate with the password actually set
  477. * @return integer returns tl::OK if the password's match, else errorcode
  478. */
  479. public function comparePassword($pwd)
  480. {
  481. if (self::isPasswordMgtExternal())
  482. return self::S_PWDMGTEXTERNAL;
  483. if ($this->getPassword($pwd) == $this->encryptPassword($pwd))
  484. return tl::OK;
  485. return self::E_PWDDONTMATCH;
  486. }
  487. public function checkDetails(&$db)
  488. {
  489. $this->firstName = trim($this->firstName);
  490. $this->lastName = trim($this->lastName);
  491. $this->emailAddress = trim($this->emailAddress);
  492. $this->locale = trim($this->locale);
  493. $this->isActive = intval($this->isActive);
  494. $this->login = trim($this->login);
  495. $result = self::checkEmailAddress($this->emailAddress);
  496. if ($result >= tl::OK)
  497. {
  498. $result = $this->checkLogin($this->login);
  499. }
  500. if ($result >= tl::OK && !$this->dbID)
  501. {
  502. $result = self::doesUserExist($db,$this->login) ? self::E_LOGINALREADYEXISTS : tl::OK;
  503. }
  504. if ($result >= tl::OK)
  505. {
  506. $result = self::checkFirstName($this->firstName);
  507. }
  508. if ($result >= tl::OK)
  509. {
  510. $result = self::checkLastName($this->lastName);
  511. }
  512. return $result;
  513. }
  514. public function checkLogin($login)
  515. {
  516. $result = tl::OK;
  517. $login = trim($login);
  518. if ($login == "" || (tlStringLen($login) > $this->maxLoginLength))
  519. $result = self::E_LOGINLENGTH;
  520. else if (!preg_match($this->loginRegExp,$login)) //Only allow a basic set of characters
  521. $result = self::E_NOTALLOWED;
  522. return $result;
  523. }
  524. /**
  525. * Returns the id of the effective role in the context of ($tproject_id,$tplan_id)
  526. *
  527. * @param resource &$db reference to database handler
  528. * @param integer $tproject_id the testproject id
  529. * @param integer $tplan_id the plan id
  530. *
  531. * @return integer tlRole the effective role
  532. */
  533. function getEffectiveRole(&$db,$tproject_id,$tplan_id)
  534. {
  535. $tprojects_role = $this->tprojectRoles;
  536. $tplans_role = $this->tplanRoles;
  537. $effective_role = $this->globalRole;
  538. if(!is_null($tplans_role) && isset($tplans_role[$tplan_id]))
  539. $effective_role = $tplans_role[$tplan_id];
  540. else if(!is_null($tprojects_role) && isset($tprojects_role[$tproject_id]))
  541. $effective_role = $tprojects_role[$tproject_id];
  542. return $effective_role;
  543. }
  544. /**
  545. * Gets all userids of users with a certain testplan role @TODO WRITE RIGHT COMMENTS FROM START
  546. *
  547. * @param resource &$db reference to database handler
  548. * @return array returns array of userids
  549. **/
  550. protected function getUserNamesWithTestPlanRole(&$db)
  551. {
  552. $sql = "SELECT DISTINCT id FROM {$this->tables['users']} users," .
  553. " {$this->tables['user_testplan_roles']} user_testplan_roles " .
  554. " WHERE users.id = user_testplan_roles.user_id";
  555. $sql .= " AND user_testplan_roles.role_id = {$this->dbID}";
  556. $idSet = $db->fetchColumnsIntoArray($sql,"id");
  557. return $idSet;
  558. }
  559. /**
  560. * Get a list of names with a defined project right (for example for combo-box)
  561. * used by ajax script getUsersWithRight.php
  562. *
  563. * @param integer $db DB Identifier
  564. * @param string $rightNick key corresponding with description in rights table
  565. * @param integer $testprojectID Identifier of project
  566. *
  567. * @return array list of user IDs and names
  568. *
  569. * @todo fix the case that user has default role with a right but project role without
  570. * i.e. he should be listed
  571. */
  572. public function getNamesForProjectRight(&$db,$rightNick,$testprojectID = null)
  573. {
  574. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  575. if (is_null($testprojectID))
  576. {
  577. tLog( $debugMsg . ' requires Test Project ID defined','ERROR');
  578. return null;
  579. }
  580. $output = array();
  581. //get users for default roles
  582. $sql = "/* $debugMsg */ SELECT DISTINCT u.id,u.login,u.first,u.last FROM {$this->tables['users']} u" .
  583. " JOIN {$this->tables['role_rights']} a ON a.role_id=u.role_id" .
  584. " JOIN {$this->tables['rights']} b ON a.right_id = b.id " .
  585. " WHERE b.description='{$rightNick}'";
  586. $defaultRoles = $db->fetchRowsIntoMap($sql,'id');
  587. // get users for project roles
  588. $sql = "/* $debugMsg */ SELECT DISTINCT u.id,u.login,u.first,u.last FROM {$this->tables['users']} u" .
  589. " JOIN {$this->tables['user_testproject_roles']} p ON p.user_id=u.id" .
  590. " AND p.testproject_id=" . $testprojectID .
  591. " JOIN {$this->tables['role_rights']} a ON a.role_id=p.role_id" .
  592. " JOIN {$this->tables['rights']} b ON a.right_id = b.id " .
  593. " WHERE b.description='{$rightNick}'";
  594. $projectRoles = $db->fetchRowsIntoMap($sql,'id');
  595. // merge arrays
  596. // the next function is available from php53 but we support php52
  597. // $output = array_replace($output1, $output2);
  598. if( !is_null($projectRoles) )
  599. {
  600. foreach($projectRoles as $k => $v)
  601. {
  602. if( !isset($defaultRoles[$k]) )
  603. {
  604. $defaultRoles[$k] = $v;
  605. }
  606. }
  607. }
  608. // format for ext-js combo-box (remove associated array)
  609. // foreach($defaultRoles as $k => $v)
  610. // {
  611. // $output[] = $v;
  612. // }
  613. $output = array_values($defaultRoles);
  614. return $output;
  615. }
  616. /**
  617. * Get a list of all names
  618. * used for replacement user ID by user login
  619. *
  620. * @param integer $db DB Identifier
  621. * @return array list of user IDs and names
  622. */
  623. public function getNames(&$db)
  624. {
  625. $sql = "SELECT id,login,first,last FROM {$this->tables['users']}";
  626. $output = $db->fetchRowsIntoMap($sql,'id');
  627. return $output;
  628. }
  629. /**
  630. * check right on effective role for user, using test project and test plan,
  631. * means that check right on effective role.
  632. *
  633. * @return string|null 'yes' or null
  634. */
  635. function hasRight(&$db,$roleQuestion,$tprojectID = null,$tplanID = null)
  636. {
  637. global $g_propRights_global;
  638. global $g_propRights_product;
  639. $userGlobalRights = (array)$this->globalRole->rights;
  640. $globalRights = array();
  641. foreach($userGlobalRights as $right)
  642. {
  643. $globalRights[] = $right->name;
  644. }
  645. if (!is_null($tplanID))
  646. {
  647. $testPlanID = $tplanID;
  648. }
  649. else
  650. {
  651. //@TODO schlundus, should not be there
  652. // 20090726 - franciscom -> yes must be moved ASAP
  653. $testPlanID = isset($_SESSION['testPlanId']) ? $_SESSION['testPlanId'] : 0;
  654. }
  655. $userTestPlanRoles = $this->tplanRoles;
  656. if (!is_null($tprojectID))
  657. {
  658. $testprojectID = $tprojectID;
  659. }
  660. else
  661. {
  662. //@TODO schlundus, should not be there
  663. $testprojectID = isset($_SESSION['testprojectID']) ? $_SESSION['testprojectID'] : 0;
  664. }
  665. $allRights = $globalRights;
  666. $userTestProjectRoles = $this->tprojectRoles;
  667. /* if $testprojectID == -1 we dont check rights at test project level! */
  668. if (isset($userTestProjectRoles[$testprojectID]))
  669. {
  670. $userTestProjectRights = (array)$userTestProjectRoles[$testprojectID]->rights;
  671. $testProjectRights = array();
  672. foreach($userTestProjectRights as $right)
  673. {
  674. $testProjectRights[] = $right->name;
  675. }
  676. //subtract global rights
  677. $testProjectRights = array_diff($testProjectRights,array_keys($g_propRights_global));
  678. propagateRights($globalRights,$g_propRights_global,$testProjectRights);
  679. $allRights = $testProjectRights;
  680. }
  681. /* if $tplanID == -1 we dont check rights at tp level! */
  682. if (isset($userTestPlanRoles[$testPlanID]))
  683. {
  684. $userTestPlanRights = (array) $userTestPlanRoles[$testPlanID]->rights;
  685. $testPlanRights = array();
  686. foreach($userTestPlanRights as $right)
  687. {
  688. $testPlanRights[] = $right->name;
  689. }
  690. //subtract test projects rights
  691. $testPlanRights = array_diff($testPlanRights,array_keys($g_propRights_product));
  692. propagateRights($allRights,$g_propRights_product,$testPlanRights);
  693. $allRights = $testPlanRights;
  694. }
  695. return checkForRights($allRights,$roleQuestion);
  696. }
  697. /**
  698. * get array with accessible test plans for user on a test project,
  699. * analising user roles.
  700. *
  701. * @param resource $db database handler
  702. * @param int testprojectID
  703. * @param int testplanID: default null.
  704. * Used as filter when you want to check if this test plan
  705. * is accessible.
  706. *
  707. * @param map options keys :
  708. * 'output' => null -> get numeric array
  709. * => map => map indexed by testplan id
  710. * => combo => map indexed by testplan id and only returns name
  711. *
  712. * @return array if 0 accessible test plans => null
  713. */
  714. function getAccessibleTestPlans(&$db,$testprojectID,$testplanID=null, $options=null)
  715. {
  716. $debugTag = 'Class:' . __CLASS__ . '- Method:' . __FUNCTION__ . '-';
  717. $my['options'] = array( 'output' => null);
  718. $my['options'] = array_merge($my['options'], (array)$options);
  719. $fields2get = ' NH.id, NH.name ';
  720. if( $my['options']['output'] != 'combo' )
  721. {
  722. $fields2get .= ' ,TPLAN.active, 0 AS selected ';
  723. }
  724. $sql = " /* $debugTag */ SELECT {$fields2get} " .
  725. " FROM {$this->tables['nodes_hierarchy']} NH" .
  726. " JOIN {$this->tables['testplans']} TPLAN ON NH.id=TPLAN.id " .
  727. " LEFT OUTER JOIN {$this->tables['user_testplan_roles']} USER_TPLAN_ROLES" .
  728. " ON TPLAN.id = USER_TPLAN_ROLES.testplan_id " .
  729. " AND USER_TPLAN_ROLES.user_id = $this->dbID WHERE active=1 AND ";
  730. $sql .= " testproject_id = {$testprojectID} AND ";
  731. if (!is_null($testplanID))
  732. {
  733. $sql .= " NH.id = {$testplanID} AND ";
  734. }
  735. $globalNoRights = ($this->globalRoleID == TL_ROLES_NO_RIGHTS);
  736. $projectNoRights = 0;
  737. $analyseGlobalRole = 1;
  738. // 20100704 - franciscom
  739. // BUGID 3526
  740. //
  741. // If user has a role for $testprojectID, then we DO NOT HAVE to check for globalRole
  742. // if( ($analyseGlobalRole = isset($this->tprojectRoles[$testprojectID]->dbID)) )
  743. // {
  744. // $projectNoRights = ($this->tprojectRoles[$testprojectID]->dbID == TL_ROLES_NO_RIGHTS);
  745. // }
  746. // Looking to the code on 1.8.5, seems this has been introduced on some refactoring
  747. if( isset($this->tprojectRoles[$testprojectID]->dbID) )
  748. {
  749. $analyseGlobalRole = 0;
  750. $projectNoRights = ($this->tprojectRoles[$testprojectID]->dbID == TL_ROLES_NO_RIGHTS);
  751. }
  752. // User can have NO RIGHT on test project under analisys ($testprojectID), in this situation he/she
  753. // has to have a role at Test Plan level in order to access one or more test plans
  754. // that belong to $testprojectID.
  755. //
  756. // Other situation: he/she has been created with role without rights ($globalNoRights)
  757. //
  758. if( $projectNoRights || ($analyseGlobalRole && $globalNoRights))
  759. {
  760. $sql .= "(role_id IS NOT NULL AND role_id != ".TL_ROLES_NO_RIGHTS.")";
  761. }
  762. else
  763. {
  764. // in this situation, do we are hineriting role from testprojectID ?
  765. $sql .= "(role_id IS NULL OR role_id != ".TL_ROLES_NO_RIGHTS.")";
  766. }
  767. $sql .= " ORDER BY name";
  768. switch($my['options']['output'])
  769. {
  770. case 'map':
  771. $testPlanSet = $db->fetchRowsIntoMap($sql,'id');
  772. break;
  773. case 'combo':
  774. $testPlanSet = $db->fetchColumnsIntoMap($sql,'id','name');
  775. break;
  776. default:
  777. $testPlanSet = $db->get_recordset($sql);
  778. break;
  779. }
  780. return $testPlanSet;
  781. }
  782. /**
  783. * Checks the correctness of an email address
  784. *
  785. * @param string $email
  786. * @return integer returns tl::OK on success, errorcode else
  787. */
  788. static public function checkEmailAddress($email)
  789. {
  790. $result = is_blank($email) ? self::E_EMAILLENGTH : tl::OK;
  791. if ($result == tl::OK)
  792. {
  793. $matches = array();
  794. $email_regex = config_get('validation_cfg')->user_email_valid_regex_php;
  795. if (!preg_match($email_regex,$email,$matches))
  796. {
  797. $result = self::E_EMAILFORMAT;
  798. }
  799. }
  800. return $result;
  801. }
  802. static public function checkFirstName($first)
  803. {
  804. return is_blank($first) ? self::E_FIRSTNAMELENGTH : tl::OK;
  805. }
  806. static public function checkLastName($last)
  807. {
  808. return is_blank($last) ? self::E_LASTNAMELENGTH : tl::OK;
  809. }
  810. static public function doesUserExist(&$db,$login)
  811. {
  812. $user = new tlUser();
  813. $user->login = $login;
  814. if ($user->readFromDB($db,self::USER_O_SEARCH_BYLOGIN) >= tl::OK)
  815. {
  816. return $user->dbID;
  817. }
  818. return null;
  819. }
  820. static public function getByID(&$db,$id,$detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  821. {
  822. return tlDBObject::createObjectFromDB($db,$id,__CLASS__,self::TLOBJ_O_SEARCH_BY_ID,$detailLevel);
  823. }
  824. static public function getByIDs(&$db,$ids,$detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  825. {
  826. $users = null;
  827. for($i = 0;$i < sizeof($ids);$i++)
  828. {
  829. $id = $ids[$i];
  830. $user = tlDBObject::createObjectFromDB($db,$id,__CLASS__,self::TLOBJ_O_SEARCH_BY_ID,$detailLevel);
  831. if ($user)
  832. $users[$id] = $user;
  833. }
  834. return $users ? $users : null;
  835. }
  836. static public function getAll(&$db,$whereClause = null,$column = null,$orderBy = null,
  837. $detailLevel = self::TLOBJ_O_GET_DETAIL_FULL)
  838. {
  839. $tables = tlObject::getDBTables('users');
  840. $sql = " SELECT id FROM {$tables['users']} ";
  841. if (!is_null($whereClause))
  842. {
  843. $sql .= ' '.$whereClause;
  844. }
  845. $sql .= is_null($orderBy) ? " ORDER BY login " : $orderBy;
  846. return tlDBObject::createObjectsFromDBbySQL($db,$sql,'id',__CLASS__,true,$detailLevel);
  847. }
  848. /**
  849. */
  850. public function setActive(&$db,$value)
  851. {
  852. $booleanVal = intval($value) > 0 ? 1 : 0;
  853. $sql = " UPDATE {$this->tables['users']} SET active = {$booleanVal} " .
  854. " WHERE id = " . $this->dbID;
  855. $result = $db->exec_query($sql);
  856. }
  857. /**
  858. * Writes user password into the database
  859. *
  860. * @param resource &$db reference to database handler
  861. * @return integer tl::OK if no problem written to the db, else error code
  862. */
  863. public function writePasswordToDB(&$db)
  864. {
  865. if($this->dbID)
  866. {
  867. $sql = "UPDATE {$this->tables['users']} " .
  868. " SET password = ". "'" . $db->prepare_string($this->password) . "'";
  869. $sql .= " WHERE id = " . $this->dbID;
  870. $result = $db->exec_query($sql);
  871. }
  872. $result = $result ? tl::OK : self::E_DBERROR;
  873. return $result;
  874. }
  875. }
  876. ?>