PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Adapto/Attribute/Profile.php

http://github.com/egeniq/adapto
PHP | 644 lines | 366 code | 95 blank | 183 comment | 71 complexity | 713d6a4b4acda8f7fe116b9ddf92a81c MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Adapto Toolkit.
  4. * Detailed copyright and licensing information can be found
  5. * in the doc/COPYRIGHT and doc/LICENSE files which should be
  6. * included in the distribution.
  7. *
  8. * @package adapto
  9. * @subpackage attributes
  10. *
  11. * @copyright (c)2000-2004 Ibuildings.nl BV
  12. * @license http://www.achievo.org/atk/licensing ATK Open Source License
  13. *
  14. */
  15. /**
  16. * The Adapto_Attribute_Profile is an attribute to edit a security profile.
  17. * The best way to use it is inside the class where you edit your
  18. * profile or usergroup records.
  19. *
  20. * @author ijansch
  21. * @package adapto
  22. * @subpackage attributes
  23. *
  24. */
  25. class Adapto_Attribute_Profile extends Adapto_Attribute
  26. {
  27. public $m_parentAttrName; // defaulted to public
  28. public $m_accessField; // defaulted to public
  29. /**
  30. * Constructor
  31. *
  32. * @param string $name The name of the attribute
  33. * @param string $parentAttrName
  34. * @param int $flags The flags of this attribute
  35. * @return Adapto_Attribute_Profile
  36. */
  37. public function __construct($name, $parentAttrName = "", $flags = 0)
  38. {
  39. if (is_numeric($parentAttrName)) {
  40. $flags = $parentAttrName;
  41. $parentAttrName = "";
  42. }
  43. parent::__construct($name, $flags | AF_HIDE_SEARCH | AF_HIDE_LIST);
  44. $this->m_parentAttrName = $parentAttrName;
  45. $this->m_accessField = Adapto_Config::getGlobal('auth_accessfield');
  46. if (empty($this->m_accessField))
  47. $this->m_accessField = Adapto_Config::getGlobal('auth_levelfield');
  48. }
  49. /**
  50. * Load this record
  51. *
  52. * @param atkDb $db The database object
  53. * @param array $record The record
  54. * @return array Array with loaded values
  55. */
  56. function load(&$db, $record)
  57. {
  58. $query = "SELECT *
  59. FROM " . Adapto_Config::getGlobal("auth_accesstable") . "
  60. WHERE " . $this->m_accessField . "='" . $record[$this->m_ownerInstance->primaryKeyField()] . "'";
  61. $result = Array();
  62. $rows = $db->getrows($query);
  63. for ($i = 0; $i < count($rows); $i++) {
  64. $result[$rows[$i]["entity"]][] = $rows[$i]["action"];
  65. }
  66. return $result;
  67. }
  68. /**
  69. * Get child groups
  70. *
  71. * @param atkDb $db The database object
  72. * @param int $id The id to search for
  73. * @return array
  74. */
  75. function getChildGroups(&$db, $id)
  76. {
  77. $result = array();
  78. return $result;
  79. $query = "SELECT " . $this->m_ownerInstance->primaryKeyField() . " " . "FROM " . $this->m_ownerInstance->m_table . " " . $rows = $db->getRows($query);
  80. foreach ($rows as $row) {
  81. }
  82. return $result;
  83. }
  84. /**
  85. * Store the value of this attribute in the database
  86. *
  87. * @param atkDb $db The database object
  88. * @param array $record The record which holds the values to store
  89. * @param string $mode The mode we're in
  90. * @return bool True if succesfull, false if not
  91. */
  92. function store(&$db, $record, $mode)
  93. {
  94. global $g_user;
  95. // Read the current actions available/editable and user rights before changing them
  96. $isAdmin = ($g_user['name'] == 'administrator' || $this->canGrantAll());
  97. $allActions = $this->getAllActions($record, false);
  98. $editableActions = $this->getEditableActions($record);
  99. $delquery = "DELETE FROM " . Adapto_Config::getGlobal("auth_accesstable") . "
  100. WHERE " . $this->m_accessField . "='" . $record[$this->m_ownerInstance->primaryKeyField()] . "'";
  101. if ($db->query($delquery)) {
  102. $checked = $record[$this->fieldName()];
  103. $children = array();
  104. if (!empty($this->m_parentAttrName))
  105. $children = $this->getChildGroups($db, $record[$this->m_ownerInstance->primaryKeyField()]);
  106. foreach ($checked as $entity => $actions) {
  107. $actions = array_unique($actions);
  108. $entityModule = getEntityModule($entity);
  109. $entityType = getEntityType($entity);
  110. $validActions = array();
  111. if (is_array($allActions[$entityModule][$entityType]))
  112. $validActions = array_intersect($actions, $allActions[$entityModule][$entityType]);
  113. // If you're not an admin, leave out all actions which are not editable (none if no editable actions available)
  114. if (!$isAdmin)
  115. $validActions = isset($editableActions[$entityModule][$entityType]) ? array_intersect($validActions, $editableActions[$entityModule][$entityType])
  116. : array();
  117. foreach ($validActions as $action) {
  118. $query = "INSERT INTO " . Adapto_Config::getGlobal("auth_accesstable") . " (entity, action, " . $this->m_accessField . ") ";
  119. $query .= "VALUES ('" . $db->escapeSQL($entity) . "','" . $db->escapeSQL($action) . "','"
  120. . $record[$this->m_ownerInstance->primaryKeyField()] . "')";
  121. if (!$db->query($query)) {
  122. // error.
  123. return false;
  124. }
  125. }
  126. if (count($children) > 0 && count($validActions) > 0) {
  127. $query = "DELETE FROM " . Adapto_Config::getGlobal("auth_accesstable") . " " . "WHERE " . $this->m_accessField . " IN (" . implode(",", $children) . ") "
  128. . "AND entity = '" . $db->escapeSQL($entity) . "' " . "AND action NOT IN ('" . implode("','", $validActions) . "')";
  129. if (!$db->query($query)) {
  130. // error.
  131. return false;
  132. }
  133. }
  134. }
  135. }
  136. return true;
  137. }
  138. /**
  139. * Returns a piece of html code for hiding this attribute in an HTML form,
  140. * while still posting its value. (<input type="hidden">)
  141. *
  142. * @param array $record The record that holds the value for this attribute
  143. * @param String $fieldprefix The fieldprefix to put in front of the name
  144. * of any html form element for this attribute.
  145. * @return String A piece of htmlcode with hidden form elements that post
  146. * this attribute's value without showing it.
  147. */
  148. function hide($record = "", $fieldprefix = "")
  149. {
  150. // get checks
  151. $checked = $record[$this->fieldName()];
  152. // rebuild hidden fields from checked boxes
  153. $rights = "";
  154. foreach ($checked as $key => $val) {
  155. for ($i = 0; $i <= count($val) - 1; $i++) {
  156. $value = $key . "." . $val[$i];
  157. $rights .= '<input type="hidden" name="rights[]" value="' . $value . '">';
  158. }
  159. }
  160. return $rights;
  161. }
  162. /**
  163. * Retrieve all possible module/entity actions.
  164. *
  165. * @param array $record The record
  166. * @return array Array with actions
  167. */
  168. function getAllActions($record, $splitPerSection = false)
  169. {
  170. global $g_modules, $g_moduleflags, $g_entitys;
  171. $result = array();
  172. // hierarchic groups, only return actions of parent (if this record has a parent)
  173. $parentAttr = $this->m_parentAttrName;
  174. if (!empty($parentAttr) && is_numeric($record[$parentAttr])) {
  175. $db = &atkGetDb();
  176. $query = "SELECT DISTINCT entity, action FROM " . Adapto_Config::getGlobal("auth_accesstable") . " " . "WHERE " . $this->m_accessField . " = "
  177. . $record[$parentAttr];
  178. $rows = $db->getRows($query);
  179. foreach ($rows as $row) {
  180. $module = getEntityModule($row['entity']);
  181. $entity = getEntityType($row['entity']);
  182. $result[$module][$module][$entity][] = $row['action'];
  183. }
  184. }
  185. // non-hierarchic groups, or root
  186. else {
  187. // include entity information
  188. require_once(Adapto_Config::getGlobal("atkroot") . "atk/atkentitytools.inc");
  189. if (file_exists("config.entitys.inc"))
  190. include_once("config.entitys.inc");
  191. // get entitys for each module
  192. foreach (array_keys($g_modules) as $module) {
  193. if (!isset($g_moduleflags[$module]) || !hasFlag($g_moduleflags[$module], MF_NORIGHTS)) {
  194. $instance = &getModule($module);
  195. if (method_exists($instance, "getEntitys"))
  196. $instance->getEntitys();
  197. }
  198. }
  199. // retrieve all actions after we registered all actions
  200. $result = $g_entitys;
  201. }
  202. if (!$splitPerSection) {
  203. $temp = array();
  204. foreach ($result as $section => $modules) {
  205. foreach ($modules as $module => $entitys) {
  206. if (!is_array($temp[$module])) {
  207. $temp[$module] = array();
  208. }
  209. $temp[$module] = array_merge($temp[$module], $entitys);
  210. }
  211. }
  212. $result = $temp;
  213. }
  214. return $result;
  215. }
  216. /**
  217. * Returns a list of actions that should be edittable by the user.
  218. *
  219. * @param array $record The record
  220. * @return array Array with editable actions
  221. */
  222. function getEditableActions($record)
  223. {
  224. $user = getUser();
  225. $levels = "";
  226. if (!is_array($user['level']))
  227. $levels = "'" . $user['level'] . "'";
  228. else
  229. $levels = "'" . implode("','", $user['level']) . "'";
  230. // retrieve editable actions by user's levels
  231. $db = &atkGetDb();
  232. $query = "SELECT DISTINCT entity, action FROM " . Adapto_Config::getGlobal("auth_accesstable") . " WHERE " . $this->m_accessField . " IN (" . $levels . ")";
  233. $rows = $db->getRows($query);
  234. $result = array();
  235. foreach ($rows as $row) {
  236. $module = getEntityModule($row['entity']);
  237. $entity = getEntityType($row['entity']);
  238. $result[$module][$entity][] = $row['action'];
  239. }
  240. return $result;
  241. }
  242. /**
  243. * Initially use an empty rights array.
  244. *
  245. * @return array initial rights
  246. */
  247. function initialValue()
  248. {
  249. return array();
  250. }
  251. /**
  252. * Returns the currently selected actions.
  253. *
  254. * @param array $record The record
  255. * @return array array with selected actions
  256. */
  257. function getSelectedActions($record)
  258. {
  259. $selected = $record[$this->fieldName()];
  260. $result = array();
  261. foreach ($selected as $entity => $actions) {
  262. $module = getEntityModule($entity);
  263. $entity = getEntityType($entity);
  264. $result[$module][$entity] = $actions;
  265. }
  266. return $result;
  267. }
  268. /**
  269. * Display rights.
  270. * It will only display the rights & entitys that are selected for the user.
  271. *
  272. * @param array $record
  273. *
  274. * @return string Displayable string
  275. */
  276. public function display($record)
  277. {
  278. $user = getUser();
  279. $page = &atkPage::getInstance();
  280. $page->register_script(Adapto_Config::getGlobal("atkroot") . "atk/javascript/class.atkprofileattribute.js.php");
  281. $this->_restoreDivStates($page);
  282. $result = '';
  283. $isAdmin = ($user['name'] == 'administrator' || $this->canGrantAll());
  284. $allActions = $this->getAllActions($record, false);
  285. $editableActions = $this->getEditableActions($record);
  286. $selectedActions = $this->getSelectedActions($record);
  287. $showModule = count($allActions) > 1 && ($isAdmin || count($editableActions) > 1);
  288. $firstModule = true;
  289. foreach ($allActions as $module => $entitys) {
  290. // If we have more then one module, split up the module results by collapsable div's
  291. if ($showModule) {
  292. $result .= "<br><hr>";
  293. if ($firstModule)
  294. $firstModule = false;
  295. else
  296. $result .= '</div><br>';
  297. $result .= '<b><a href="javascript:void(0)" onclick="profile_swapProfileDiv(\'div_' . $module . "', '" . Adapto_Config::getGlobal('atkroot')
  298. . '\'); return false;"><img src="' . Adapto_Config::getGlobal('atkroot') . 'atk/images/plus.gif" border="0" id="img_div_' . $module
  299. . '></a>&nbsp;</b>' . atktext(array('title_' . $module, $module), $module) . '<br>';
  300. $result .= "<div id='div_$module' name='div_$module' style='display: none;'>";
  301. $result .= "<input type='hidden' name=\"divstate['div_$module']\" id=\"divstate['div_$module']\" value='closed' />";
  302. $result .= "<br>";
  303. }
  304. foreach ($entitys as $entity => $actions) {
  305. $showBox = $isAdmin
  306. || count(array_intersect($actions, (is_array($editableActions[$module][$entity]) ? $editableActions[$module][$entity] : array()))) > 0;
  307. $display_entity_str = false;
  308. $display_tabs_str = false;
  309. $entity_result = '';
  310. $permissions_string = '';
  311. $tab_permissions_string = '';
  312. foreach ($actions as $action) {
  313. $isSelected = isset($selectedActions[$module][$entity]) && in_array($action, $selectedActions[$module][$entity]);
  314. // If the action of an entity is selected for this user we will show the entity,
  315. // otherwise we won't
  316. if ($isSelected) {
  317. $display_entity_str = true;
  318. if (substr($action, 0, 4) == "tab_") {
  319. $display_tabs_str = true;
  320. $tab_permissions_string .= $this->permissionName($action, $entity, $module) . '&nbsp;&nbsp;&nbsp;';
  321. } else {
  322. $permissions_string .= $this->permissionName($action, $entity, $module) . '&nbsp;&nbsp;&nbsp;';
  323. }
  324. }
  325. }
  326. if ($showBox) {
  327. $entity_result .= "<b>" . atktext($entity, $module) . "</b><br>";
  328. $entity_result .= $permissions_string;
  329. if ($display_tabs_str)
  330. $entity_result .= "<br>Tabs:&nbsp;" . $tab_permissions_string;
  331. $entity_result .= "<br /><br />\n";
  332. } else {
  333. $entity_result .= $permissions_string;
  334. if ($display_tabs_str)
  335. $entity_result .= "<br>Tabs:&nbsp;" . $tab_permissions_string;
  336. }
  337. if ($display_entity_str)
  338. $result .= $entity_result;
  339. }
  340. }
  341. return $result;
  342. }
  343. /**
  344. * Returns a piece of html code that can be used in a form to edit this
  345. * attribute's value.
  346. *
  347. * @param array $record The record that holds the value for this attribute.
  348. * @param String $fieldprefix The fieldprefix to put in front of the name
  349. * of any html form element for this attribute.
  350. * @param String $mode The mode we're in ('add' or 'edit')
  351. * @return String A piece of htmlcode for editing this attribute
  352. */
  353. function edit($record = "", $fieldprefix = "", $mode = "")
  354. {
  355. $user = getUser();
  356. $page = &atkPage::getInstance();
  357. $page->register_script(Adapto_Config::getGlobal("atkroot") . "atk/javascript/class.atkprofileattribute.js.php");
  358. $this->_restoreDivStates($page);
  359. $result = '<div align="right">
  360. [<a href="javascript:void(0)" onclick="profile_checkAll(\'' . $this->fieldName() . '\'); return false;">' . atktext("check_all")
  361. . '</a> | <a href="javascript:void(0)" onclick="profile_checkNone(\'' . $this->fieldName() . '\'); return false;">' . atktext("check_none")
  362. . '</a> | <a href="javascript:void(0)" onclick="profile_checkInvert(\'' . $this->fieldName() . '\'); return false;">'
  363. . atktext("invert_selection") . '</a>]</div>';
  364. $isAdmin = ($user['name'] == 'administrator' || $this->canGrantAll());
  365. $allActions = $this->getAllActions($record, true);
  366. $editableActions = $this->getEditableActions($record);
  367. $selectedActions = $this->getSelectedActions($record);
  368. $showSection = count($allActions) > 1;
  369. foreach ($allActions as $section => $modules) {
  370. if ($showSection) {
  371. $result .= "</div><br>";
  372. $result .= "<span onclick=\"profile_swapProfileDiv('div_$section','" . Adapto_Config::getGlobal("atkroot")
  373. . "');\" style=\"cursor: pointer; font-size: 110%; font-weight: bold\"><img src=\"" . Adapto_Config::getGlobal("atkroot")
  374. . "atk/images/plus.gif\" border=\"0\" id=\"img_div_$section\">&nbsp;" . atktext(array("title_$section", $section), $section)
  375. . "</span><br/>";
  376. $result .= "<div id='div_$section' name='div_$section' style='display: none; padding-left: 15px'>";
  377. $result .= "<input type='hidden' name=\"divstate['div_$section']\" id=\"divstate['div_$section']\" value='closed' />";
  378. $result .= '<div style="font-size: 80%; margin-top: 4px; margin-bottom: 4px" >
  379. [<a style="font-size: 100%" href="javascript:void(0)" onclick="profile_checkAllByValue(\'' . $this->fieldName() . '\',\'' . $section
  380. . '.\'); return false;">' . atktext("check_all", "atk")
  381. . '</a> | <a style="font-size: 100%" href="javascript:void(0)" onclick="profile_checkNoneByValue(\'' . $this->fieldName() . '\',\''
  382. . $section . '.\'); return false;">' . atktext("check_none", "atk")
  383. . '</a> | <a style="font-size: 100%" href="javascript:void(0)" onclick="profile_checkInvertByValue(\'' . $this->fieldName() . '\',\''
  384. . $section . '.\'); return false;">' . atktext("invert_selection", "atk") . '</a>]</div>';
  385. $result .= "<br>";
  386. }
  387. foreach ($modules as $module => $entitys) {
  388. foreach ($entitys as $entity => $actions) {
  389. $showBox = $isAdmin
  390. || count(array_intersect($actions, (is_array($editableActions[$module][$entity]) ? $editableActions[$module][$entity] : array()))) > 0;
  391. if ($showBox)
  392. $result .= "<b>" . atktext($entity, $module) . "</b><br>";
  393. $tabs_str = "";
  394. $display_tabs_str = false;
  395. // Draw action checkboxes
  396. foreach ($actions as $action) {
  397. $temp_str = "";
  398. $isEditable = $isAdmin || Adapto_in_array($action, $editableActions[$module][$entity]);
  399. $isSelected = isset($selectedActions[$module][$entity]) && in_array($action, $selectedActions[$module][$entity]);
  400. if ($isEditable) {
  401. if (substr($action, 0, 4) == "tab_")
  402. $display_tabs_str = true;
  403. $temp_str .= '<input type="checkbox" name="' . $this->formName() . '[]" ' . $this->getCSSClassAttribute("atkcheckbox") . ' value="'
  404. . $section . "." . $module . "." . $entity . "." . $action . '" ';
  405. $temp_str .= ($isSelected ? ' checked="checked"' : '') . '></input> ';
  406. $temp_str .= $this->permissionName($action, $entity, $module) . '&nbsp;&nbsp;&nbsp;';
  407. }
  408. if (substr($action, 0, 4) == "tab_")
  409. $tabs_str .= $temp_str;
  410. else
  411. $result .= $temp_str;
  412. }
  413. if ($display_tabs_str)
  414. $result .= "<br>Tabs:&nbsp;";
  415. $result .= $tabs_str;
  416. if ($showBox)
  417. $result .= "<br /><br />\n";
  418. }
  419. }
  420. }
  421. $result = '<div style="min-width: 700px">' . $result . '</div>';
  422. return $result;
  423. }
  424. /**
  425. * Return the translated name of a permission.
  426. *
  427. * @param string $action The name of the action
  428. * @param string $entityname The name of the entity
  429. * @param string $modulename The name of the module
  430. * @return String The translated permission name
  431. */
  432. function permissionName($action, $entityname = "", $modulename = "")
  433. {
  434. $keys = array('permission_' . $modulename . '_' . $entityname . '_' . $action, 'action_' . $modulename . '_' . $entityname . '_' . $action,
  435. 'permission_' . $entityname . '_' . $action, 'action_' . $entityname . '_' . $action, 'permission_' . $action, 'action_' . $action, $action);
  436. // don't use text() function of attribute, because of auto module detection
  437. $label = atktext($keys, $modulename, $entityname);
  438. return $label;
  439. }
  440. /**
  441. * Convert values from an HTML form posting to an internal value for
  442. * this attribute.
  443. *
  444. * For the regular atkAttribute, this means getting the field with the
  445. * same name as the attribute from the html posting.
  446. *
  447. * @param array $postvars The array with html posted values ($_POST, for
  448. * example) that holds this attribute's value.
  449. * @return String The internal value
  450. */
  451. function fetchValue($postvars)
  452. {
  453. $checkboxes = array();
  454. if (isset($postvars[$this->fieldName()])) {
  455. $checkboxes = $postvars[$this->fieldName()];
  456. }
  457. $actions = Array();
  458. for ($i = 0; $i < count($checkboxes); $i++) {
  459. $elems = explode(".", $checkboxes[$i]);
  460. if (count($elems) == 4) {
  461. $entity = $elems[1] . "." . $elems[2];
  462. $action = $elems[3];
  463. } else if (count($elems) == 3) {
  464. $entity = $elems[1];
  465. $action = $elems[2];
  466. } else {
  467. // never happens..
  468. Adapto_Util_Debugger::debug("profileattribute encountered incomplete combination");
  469. }
  470. $actions[$entity][] = $action;
  471. }
  472. return $actions;
  473. }
  474. /**
  475. * Retrieve the list of searchmodes supported by the attribute.
  476. *
  477. * Note that not all modes may be supported by the database driver.
  478. * Compare this list to the one returned by the databasedriver, to
  479. * determine which searchmodes may be used.
  480. *
  481. * @return array List of supported searchmodes
  482. */
  483. function getSearchModes()
  484. {
  485. // exact match and substring search should be supported by any database.
  486. // (the LIKE function is ANSI standard SQL, and both substring and wildcard
  487. // searches can be implemented using LIKE)
  488. // Possible values
  489. //"regexp","exact","substring", "wildcard","greaterthan","greaterthanequal","lessthan","lessthanequal"
  490. return array();
  491. }
  492. /**
  493. * Return the database field type of the attribute.
  494. *
  495. * Note that the type returned is a 'generic' type. Each database
  496. * vendor might have his own types, therefor, the type should be
  497. * converted to a database specific type using $db->fieldType().
  498. *
  499. * If the type was read from the table metadata, that value will
  500. * be used. Else, the attribute will analyze its flags to guess
  501. * what type it should be. If AF_AUTO_INCREMENT is set, the field
  502. * is probaly "number". If not, it's probably "string".
  503. *
  504. * @return String The 'generic' type of the database field for this
  505. * attribute.
  506. */
  507. function dbFieldType()
  508. {
  509. return "";
  510. }
  511. /**
  512. * Checks whether the current user has the 'grantall' privilege (if such a
  513. * privilege exists; this is determined by the application by setting
  514. * $config_auth_grantall_privilege.
  515. *
  516. * @return boolean
  517. */
  518. function canGrantAll()
  519. {
  520. $privilege_setting = Adapto_Config::getGlobal("auth_grantall_privilege");
  521. if ($privilege_setting != "") {
  522. global $g_securityManager;
  523. list($mod, $entity, $priv) = explode(".", $privilege_setting);
  524. return $g_securityManager->allowed($mod . "." . $entity, $priv);
  525. }
  526. return false;
  527. }
  528. /**
  529. * Restore divs states
  530. *
  531. * @param atkPage $page
  532. */
  533. function _restoreDivStates(&$page)
  534. {
  535. $postvars = &$this->m_ownerInstance->m_postvars;
  536. if (!isset($postvars['divstate']) || !is_array($postvars['divstate']) || sizeof($postvars['divstate']) == 0)
  537. return;
  538. $divstate = $postvars['divstate'];
  539. $onLoadScript = "";
  540. foreach ($divstate as $key => $value) {
  541. $key = substr($key, 2, -2);
  542. if ($value == "opened")
  543. $onLoadScript .= "profile_swapProfileDiv('$key','" . Adapto_Config::getGlobal("atkroot") . "');";
  544. }
  545. $page->register_loadscript($onLoadScript);
  546. }
  547. }
  548. ?>