From: Chuck Hagenbuch Date: Sat, 17 Jul 2010 04:38:08 +0000 (-0400) Subject: Revert "Remove DataTree code from Horde_Perms" X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=f0a65e5a0275d23e890981ebb7f30e3475dafc48;p=horde.git Revert "Remove DataTree code from Horde_Perms" This reverts commit f866a2f5cb272ffe5cd0857b84774107d0df85f9, except for removing the DataTree support from the Perms binder, which has been kept. --- diff --git a/framework/Perms/lib/Horde/Perms/Datatree.php b/framework/Perms/lib/Horde/Perms/Datatree.php new file mode 100644 index 000000000..85e5a90c1 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Datatree.php @@ -0,0 +1,248 @@ + + * @author Jan Schneider + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Datatree extends Horde_Perms +{ + /** + * Pointer to a DataTree instance to manage the different permissions. + * + * @var DataTree + */ + protected $_datatree; + + /** + * Incrementing version number if cached classes change. + * + * @var integer + */ + private $_cacheVersion = 2; + + /** + * Cache for getPermission(). + * + * @var array + */ + protected $_permsCache = array(); + + /** + * Constructor. + * + * @param array $params Configuration parameters (in addition to base + * Horde_Perms parameters): + *
+     * 'datatree' - (DataTree) A datatree object. [REQUIRED]
+     * 
+ * + * @throws Horde_Perms_Exception + */ + public function __construct($params = array()) + { + if (empty($params['datatree'])) { + throw new Horde_Perms_Exception('You must configure a DataTree backend.'); + } + + $this->_datatree = $params['datatree']; + + parent::__construct($params); + } + + /** + * Returns a new permissions object. + * + * @param string $name The permission's name. + * + * @return DataTreeObject_Permissions A new permissions object. + */ + public function newPermission($name) + { + $type = 'matrix'; + $params = null; + + if ($pos = strpos($name, ':')) { + try { + $info = $this->getApplicationPermissions(substr($name, 0, $pos)); + if (isset($info['type']) && isset($info['type'][$name])) { + $type = $info['type'][$name]; + } + + if (isset($info['params']) && isset($info['params'][$name])) { + $params = $info['params'][$name]; + } + } catch (Horde_Perms_Exception $e) {} + } + + $perm = new Horde_Perms_Permission_DataTreeObject($name, $this->_cacheVersion, $type, $params); + $perm->setCacheOb($this->_cache); + $perm->setDataTree($this->_datatree); + + return $perm; + } + + /** + * Returns a permission object corresponding to the named permission, + * with the users and other data retrieved appropriately. + * + * @param string $name The name of the permission to retrieve. + * + * @return TODO + */ + public function getPermission($name) + { + if (isset($this->_permsCache[$name])) { + return $this->_permsCache[$name]; + } + + $perm = $this->_cache->get('perm_' . $this->_cacheVersion . $name, $GLOBALS['conf']['cache']['default_lifetime']); + if ($perm === false) { + $perm = $this->_datatree->getObject($name, 'Horde_Perms_Permission_DataTreeObject'); + $perm->setCacheVersion($this->_cacheVersion); + $this->_cache->set('perm_' . $this->_cacheVersion . $name, serialize($perm), $GLOBALS['conf']['cache']['default_lifetime']); + $this->_permsCache[$name] = $perm; + } else { + $this->_permsCache[$name] = unserialize($perm); + } + + $this->_permsCache[$name]->setCacheOb($this->_cache); + $this->_permsCache[$name]->setDataTree($this->_datatree); + + return $this->_permsCache[$name]; + } + + /** + * Returns a permission object corresponding to the given unique ID, + * with the users and other data retrieved appropriately. + * + * @param integer $cid The unique ID of the permission to retrieve. + */ + public function getPermissionById($cid) + { + if ($cid == Horde_Perms::ROOT) { + return $this->newPermission(Horde_Perms::ROOT); + } + $perm = $this->_datatree->getObjectById($cid, 'Horde_Perms_Permission_DataTreeObject'); + $perm->setCacheVersion($this->_cacheVersion); + return $perm; + } + + /** + * Adds a permission to the permissions system. The permission must first + * be created with newPermission(), and have any initial users added to + * it, before this function is called. + * + * @param Horde_Perms_Permission_DataTreeObject $perm The new perm + * object. + * @throws Horde_Perms_Exception + */ + public function addPermission(Horde_Perms_Permission_DataTreeObject $perm) + { + $name = $perm->getName(); + if (empty($name)) { + throw Horde_Perms_Exception('Permission names must be non-empty.'); + } + $this->_cache->expire('perm_' . $this->_cacheVersion . $name); + $this->_cache->expire('perm_exists_' . $this->_cacheVersion . $name); + + return $this->_datatree->add($perm); + } + + /** + * Removes a permission from the permissions system permanently. + * + * @param Horde_Perms_Permission_DataTreeObject $perm The permission to + * remove. + * @param boolean $force Force to remove + * every child. + */ + public function removePermission(Horde_Perms_Permission_DataTreeObject $perm, $force = false) + { + $keys = $this->_datatree->get(DATATREE_FORMAT_FLAT, $perm->name, true); + foreach ($keys as $key) { + $this->_cache->expire('perm_' . $this->_cacheVersion . $key); + $this->_cache->expire('perm_exists_' . $this->_cacheVersion . $key); + } + + return $this->_datatree->remove($perm->name, $force); + } + + /** + * Returns the unique identifier of this permission. + * + * @param Horde_Perms_Permission_DataTreeObject $perm The permission + * object to get the + * ID of. + * + * @return integer The unique id. + */ + public function getPermissionId($permission) + { + return $this->_datatree->getId($permission->getName()); + } + + /** + * Checks if a permission exists in the system. + * + * @param string $permission The permission to check. + * + * @return boolean True if the permission exists. + */ + public function exists($permission) + { + $key = 'perm_exists_' . $this->_cacheVersion . $permission; + $exists = $this->_cache->get($key, $GLOBALS['conf']['cache']['default_lifetime']); + if ($exists === false) { + $exists = $this->_datatree->exists($permission); + $this->_cache->set($key, (string)$exists); + } + + return (bool)$exists; + } + + /** + * Returns a list of parent permissions. + * + * @param string $child The name of the child to retrieve parents for. + * + * @return array A hash with all parents in a tree format. + */ + public function getParents($child) + { + return $this->_datatree->getParents($child); + } + + /** + * Returns a child's direct parent ID. + * + * @param mixed $child Either the object, an array containing the + * path elements, or the object name for which + * to look up the parent's ID. + * + * @return mixed The unique ID of the parent or PEAR_Error on error. + */ + public function getParent($child) + { + return $this->_datatree->getParent($child); + } + + /** + * Returns all permissions of the system in a tree format. + * + * @return array A hash with all permissions in a tree format. + */ + public function getTree() + { + return $this->_datatree->get(DATATREE_FORMAT_FLAT, Horde_Perms::ROOT, true); + } + +} diff --git a/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php b/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php new file mode 100644 index 000000000..af66847b9 --- /dev/null +++ b/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php @@ -0,0 +1,590 @@ + + * @author Jan Schneider + * @category Horde + * @package Horde_Perms + */ +class Horde_Perms_Permission_DataTreeObject extends DataTreeObject +{ + /** + * Cache object. + * + * @var Horde_Cache + */ + protected $_cache; + + /** + * Constructor. Just makes sure to call the parent constructor so that + * the perm's name is set properly. + * + * @param string $name The name of the perm. + * @param string $type The permission type. + * @param array $params A hash with any parameters that the permission + * type needs. + */ + public function __construct($name, $type = 'matrix', $params = null) + { + parent::DataTreeObject($name); + + $this->data['type'] = $type; + if (is_array($params)) { + $this->data['params'] = $params; + } + } + + /** + * Don't store cache object on serialize(). + * + * @return array List of variables to serialize. + */ + public function __sleep() + { + return array_diff(array_keys(get_class_vars(__CLASS__)), array('_cache')); + } + + /** + * Sets the cache instance in the object. + * + * @param Horde_Cache $cache The cache object. + */ + public function setCacheOb(Horde_Cache $cache) + { + $this->_cache = $cache; + } + + /** + * Gets one of the attributes of the object, or null if it isn't defined. + * + * @param string $attribute The attribute to get. + * + * @return mixed The value of the attribute, or null. + */ + public function get($attribute) + { + $value = parent::get($attribute); + + return (is_null($value) && $attribute == 'type') + ? 'matrix' + : $value; + } + + /** + * Updates the permissions based on data passed in the array. + * + * @param array $perms An array containing the permissions which are to + * be updated. + */ + public function updatePermissions($perms) + { + $type = $this->get('type'); + + if ($type == 'matrix') { + /* Array of permission types to iterate through. */ + $perm_types = Horde_Perms::getPermsArray(); + } + + foreach ($perms as $perm_class => $perm_values) { + switch ($perm_class) { + case 'default': + case 'guest': + case 'creator': + if ($type == 'matrix') { + foreach ($perm_types as $val => $label) { + if (!empty($perm_values[$val])) { + $this->setPerm($perm_class, $val, false); + } else { + $this->unsetPerm($perm_class, $val, false); + } + } + } elseif (!empty($perm_values)) { + $this->setPerm($perm_class, $perm_values, false); + } else { + $this->unsetPerm($perm_class, null, false); + } + break; + + case 'u': + case 'g': + $permId = array('class' => $perm_class == 'u' ? 'users' : 'groups'); + /* Figure out what names that are stored in this permission + * class have not been submitted for an update, ie. have been + * removed entirely. */ + $current_names = isset($this->data[$permId['class']]) + ? array_keys($this->data[$permId['class']]) + : array(); + $updated_names = array_keys($perm_values); + $removed_names = array_diff($current_names, $updated_names); + + /* Remove any names that have been completely unset. */ + foreach ($removed_names as $name) { + unset($this->data[$permId['class']][$name]); + } + + /* If nothing to actually update finish with this case. */ + if (is_null($perm_values)) { + continue; + } + + /* Loop through the names and update permissions for each. */ + foreach ($perm_values as $name => $name_values) { + $permId['name'] = $name; + + if ($type == 'matrix') { + foreach ($perm_types as $val => $label) { + if (!empty($name_values[$val])) { + $this->setPerm($permId, $val, false); + } else { + $this->unsetPerm($permId, $val, false); + } + } + } elseif (!empty($name_values)) { + $this->setPerm($permId, $name_values, false); + } else { + $this->unsetPerm($permId, null, false); + } + } + break; + } + } + } + + /** + * TODO + */ + public function setPerm($permId, $permission, $update = true) + { + if (is_array($permId)) { + if (empty($permId['name'])) { + return; + } + if ($this->get('type') == 'matrix' && + isset($this->data[$permId['class']][$permId['name']])) { + $this->data[$permId['class']][$permId['name']] |= $permission; + } else { + $this->data[$permId['class']][$permId['name']] = $permission; + } + } else { + if ($this->get('type') == 'matrix' && + isset($this->data[$permId])) { + $this->data[$permId] |= $permission; + } else { + $this->data[$permId] = $permission; + } + } + + if ($update) { + $this->save(); + } + } + + /** + * TODO + */ + public function unsetPerm($permId, $permission, $update = true) + { + if (is_array($permId)) { + if (empty($permId['name'])) { + return; + } + if ($this->get('type') == 'matrix') { + if (isset($this->data[$permId['class']][$permId['name']])) { + $this->data[$permId['class']][$permId['name']] &= ~$permission; + if (empty($this->data[$permId['class']][$permId['name']])) { + unset($this->data[$permId['class']][$permId['name']]); + } + if ($update) { + $this->save(); + } + } + } else { + unset($this->data[$permId['class']][$permId['name']]); + if ($update) { + $this->save(); + } + } + } else { + if ($this->get('type') == 'matrix') { + if (isset($this->data[$permId])) { + $this->data[$permId] &= ~$permission; + if ($update) { + $this->save(); + } + } + } else { + unset($this->data[$permId]); + if ($update) { + $this->save(); + } + } + } + } + + /** + * Grants a user additional permissions to this object. + * + * @param string $user The user to grant additional permissions + * to. + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addUserPermission($user, $permission, $update = true) + { + if (empty($user)) { + return; + } + + if ($this->get('type') == 'matrix' && + isset($this->data['users'][$user])) { + $this->data['users'][$user] |= $permission; + } else { + $this->data['users'][$user] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants guests additional permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addGuestPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['guest'])) { + $this->data['guest'] |= $permission; + } else { + $this->data['guest'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants creators additional permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addCreatorPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['creator'])) { + $this->data['creator'] |= $permission; + } else { + $this->data['creator'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants additional default permissions to this object. + * + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addDefaultPermission($permission, $update = true) + { + if ($this->get('type') == 'matrix' && + isset($this->data['default'])) { + $this->data['default'] |= $permission; + } else { + $this->data['default'] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Grants a group additional permissions to this object. + * + * @param integer $groupId The id of the group to grant additional + * permissions to. + * @param integer $permission The permission (DELETE, etc.) to add. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function addGroupPermission($groupId, $permission, $update = true) + { + if (empty($groupId)) { + return; + } + + if ($this->get('type') == 'matrix' && + isset($this->data['groups'][$groupId])) { + $this->data['groups'][$groupId] |= $permission; + } else { + $this->data['groups'][$groupId] = $permission; + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that a user currently has on this object. + * + * @param string $user The user to remove the permission from. + * @param integer $permission The permission (DELETE, etc.) to + * remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeUserPermission($user, $permission, $update = true) + { + if (empty($user) || !isset($this->data['users'][$user])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['users'][$user] &= ~$permission; + if (empty($this->data['users'][$user])) { + unset($this->data['users'][$user]); + } + } else { + unset($this->data['users'][$user]); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that guests currently have on this object. + * + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeGuestPermission($permission, $update = true) + { + if (!isset($this->data['guest'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['guest'] &= ~$permission; + } else { + unset($this->data['guest']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that creators currently have on this object. + * + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeCreatorPermission($permission, $update = true) + { + if (!isset($this->data['creator'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['creator'] &= ~$permission; + } else { + unset($this->data['creator']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a default permission on this object. + * + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeDefaultPermission($permission, $update = true) + { + if (!isset($this->data['default'])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['default'] &= ~$permission; + } else { + unset($this->data['default']); + } + + if ($update) { + $this->save(); + } + } + + /** + * Removes a permission that a group currently has on this object. + * + * @param integer $groupId The id of the group to remove the + * permission from. + * @param integer $permission The permission (DELETE, etc.) to remove. + * @param boolean $update Whether to automatically update the + * backend. + */ + public function removeGroupPermission($groupId, $permission, + $update = true) + { + if (empty($groupId) || !isset($this->data['groups'][$groupId])) { + return; + } + + if ($this->get('type') == 'matrix') { + $this->data['groups'][$groupId] &= ~$permission; + if (empty($this->data['groups'][$groupId])) { + unset($this->data['groups'][$groupId]); + } + } else { + unset($this->data['groups'][$groupId]); + } + + if ($update) { + $this->save(); + } + } + + /** + * Returns an array of all user permissions on this object. + * + * @param integer $perm List only users with this permission level. + * Defaults to all users. + * + * @return array All user permissions for this object, indexed by user. + */ + public function getUserPermissions($perm = null) + { + if (!isset($this->data['users']) || !is_array($this->data['users'])) { + return array(); + } elseif (!$perm) { + return $this->data['users']; + } + + $users = array(); + foreach ($this->data['users'] as $user => $uperm) { + if ($uperm & $perm) { + $users[$user] = $uperm; + } + } + + return $users; + } + + /** + * Returns the guest permissions on this object. + * + * @return integer The guest permissions on this object. + */ + public function getGuestPermissions() + { + return empty($this->data['guest']) + ? null + : $this->data['guest']; + } + + /** + * Returns the creator permissions on this object. + * + * @return integer The creator permissions on this object. + */ + public function getCreatorPermissions() + { + return empty($this->data['creator']) + ? null + : $this->data['creator']; + } + + /** + * Returns the default permissions on this object. + * + * @return integer The default permissions on this object. + */ + public function getDefaultPermissions() + { + return empty($this->data['default']) + ? null + : $this->data['default']; + } + + /** + * Returns an array of all group permissions on this object. + * + * @param integer $perm List only users with this permission level. + * Defaults to all users. + * + * @return array All group permissions for this object, indexed by group. + */ + public function getGroupPermissions($perm = null) + { + if (!isset($this->data['groups']) || + !is_array($this->data['groups'])) { + return array(); + } elseif (!$perm) { + return $this->data['groups']; + } + + $groups = array(); + foreach ($this->data['groups'] as $group => $gperm) { + if ($gperm & $perm) { + $groups[$group] = $gperm; + } + } + + return $groups; + } + + /** + * Saves any changes to this object to the backend permanently. New + * objects are added instead. + * + * @throws Horde_Perms_Exception + */ + public function save() + { + $name = $this->getName(); + if (empty($name)) { + throw new Horde_Perms_Exception('Permission names must be non-empty'); + } + + parent::save(); + + if ($this->_cache) { + $this->_cache->expire('perm_' . $this->_cacheVersion . $name); + $this->_cache->expire('perm_exists_' . $this->_cacheVersion . $name); + } + } + +} diff --git a/framework/Perms/package.xml b/framework/Perms/package.xml index 5a13b5ed4..dc9c39dc5 100644 --- a/framework/Perms/package.xml +++ b/framework/Perms/package.xml @@ -39,8 +39,10 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + @@ -72,6 +74,10 @@ http://pear.php.net/dtd/package-2.0.xsd"> + Horde_DataTree + pear.horde.org + + Tree pear.horde.org @@ -79,8 +85,10 @@ http://pear.php.net/dtd/package-2.0.xsd"> + +