From: Michael M Slusarz Date: Tue, 1 Jun 2010 08:46:27 +0000 (-0600) Subject: Convert Group to H4 conventions X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=e322c3c80fca8144fc226407e5bc697a28a23286;p=horde.git Convert Group to H4 conventions Still needs a bunch of work, but now it should at least autoload. Also, switch to Horde_Db usage for the Sql driver. --- diff --git a/ansel/lib/Storage.php b/ansel/lib/Storage.php index 13ab3dd3e..5ecda0112 100644 --- a/ansel/lib/Storage.php +++ b/ansel/lib/Storage.php @@ -221,9 +221,9 @@ class Ansel_Storage } if ($perms) { - $groups = Group::singleton(); + $groups = Horde_Group::singleton(); $group_list = $groups->getGroupMemberships(Horde_Auth::getAuth()); - if (!($group_list instanceof PEAR_Error) && count($group_list)) { + if (count($group_list)) { foreach ($group_list as $group_id => $group_name) { $perm->addGroupPermission($group_id, $perms, false); } diff --git a/ansel/perms.php b/ansel/perms.php index 84481ea04..4306479cf 100644 --- a/ansel/perms.php +++ b/ansel/perms.php @@ -18,9 +18,7 @@ $fieldsList = array( require_once dirname(__FILE__) . '/lib/Application.php'; Horde_Registry::appInit('ansel'); -require_once 'Horde/Group.php'; - -$groups = Group::singleton(); +$groups = Horde_Group::singleton(); $auth = $injector->getInstance('Horde_Auth')->getOb(); $form = null; @@ -263,11 +261,12 @@ if ($auth->hasCapability('list')) { $userList = array(); } -$groupList = $groups->listGroups(); -asort($groupList); -if ($groupList instanceof PEAR_Error) { - Horde::logMessage($groupList, 'NOTICE'); - $groupList = array(); +$groupList = array(); +try { + $groupList = $groups->listGroups(); + asort($groupList); +} catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'NOTICE'); } require $registry->get('templates', 'horde') . '/common-header.inc'; diff --git a/folks/config/hooks.php.dist b/folks/config/hooks.php.dist index e682c7b6b..01742e6af 100644 --- a/folks/config/hooks.php.dist +++ b/folks/config/hooks.php.dist @@ -207,8 +207,7 @@ class Folks_Hooks public function prelogin($app) { - require_once 'Horde/Group.php'; - $group = Group::singleton(); + $group = Horde_Group::singleton(); $user_uid = Horde_Auth::getAuth(); switch ($app) { diff --git a/folks/perms.php b/folks/perms.php index 4bc2a9076..958588ae4 100644 --- a/folks/perms.php +++ b/folks/perms.php @@ -10,10 +10,9 @@ */ require_once dirname(__FILE__) . '/lib/base.php'; -require_once 'Horde/Group.php'; $shares = $GLOBALS['injector']->getInstance('Horde_Share')->getScope(); -$groups = &Group::singleton(); +$groups = Horde_Group::singleton(); $auth = $injector->getInstance('Horde_Auth')->getOb(); $reload = false; @@ -234,16 +233,15 @@ if ($auth->hasCapability('list')) { $userList = array(); } -if (!empty($conf['share']['any_group'])) { - $groupList = $groups->listGroups(); -} else { - $groupList = $groups->getGroupMemberships(Horde_Auth::getAuth(), true); -} -if (is_a($groupList, 'PEAR_Error')) { - Horde::logMessage($groupList, 'NOTICE'); - $groupList = array(); +$groupList = array(); +try { + $groupList = empty($conf['share']['any_group']) + ? $groups->getGroupMemberships(Horde_Auth::getAuth(), true) + : $groups->listGroups(); + asort($groupList); +} catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'NOTICE'); } -asort($groupList); require FOLKS_TEMPLATES . '/common-header.inc'; $notification->notify(array('listeners' => 'status')); diff --git a/framework/Ajax/lib/Horde/Ajax/Application/Base.php b/framework/Ajax/lib/Horde/Ajax/Application/Base.php index 11b6379ea..800cdc70e 100644 --- a/framework/Ajax/lib/Horde/Ajax/Application/Base.php +++ b/framework/Ajax/lib/Horde/Ajax/Application/Base.php @@ -133,21 +133,19 @@ abstract class Horde_Ajax_Application_Base */ public function listGroups() { - $result = new stdClass; - require_once 'Horde/Group.php'; - $horde_groups = Group::singleton(); - if (!empty($GLOBALS['conf']['share']['any_group'])) { - $groups = $horde_groups->listGroups(); - } else { - $groups = $horde_groups->getGroupMemberships(Horde_Auth::getAuth(), true); - } - if ($groups) { - if ($groups instanceof PEAR_Error) { - $groups = array(); - } + try { + $horde_groups = Horde_Group::singleton(); + $groups = empty($GLOBALS['conf']['share']['any_group']) + ? $horde_groups->getGroupMemberships(Horde_Auth::getAuth(), true) + : $horde_groups->listGroups(); asort($groups); - $result->groups = $groups; + } catch (Horde_Group_Exception $e) { + $groups = array(); } + + $result = new stdClass; + $result->groups = $groups; + return $result; } diff --git a/framework/Core/lib/Horde/Core/Factory/KolabStorage.php b/framework/Core/lib/Horde/Core/Factory/KolabStorage.php index 0babf6ab8..91b8a16a6 100644 --- a/framework/Core/lib/Horde/Core/Factory/KolabStorage.php +++ b/framework/Core/lib/Horde/Core/Factory/KolabStorage.php @@ -103,12 +103,9 @@ class Horde_Core_Factory_KolabStorage $imap = Horde_Imap_Client::factory('socket', $params); - //@todo: The Group package needs to be converted to H4 - require_once 'Horde/Group.php'; - $master = new Horde_Kolab_Storage_Driver_Imap( $imap, - Group::singleton() + Horde_Group::singleton() ); return new Horde_Kolab_Storage( diff --git a/framework/Core/lib/Horde/Core/Perms/Ui.php b/framework/Core/lib/Horde/Core/Perms/Ui.php index 617a8e0ad..d4cf22249 100644 --- a/framework/Core/lib/Horde/Core/Perms/Ui.php +++ b/framework/Core/lib/Horde/Core/Perms/Ui.php @@ -344,11 +344,11 @@ class Horde_Core_Perms_Ui /* Groups permissions. */ $perm_val = $permission->getGroupPermissions(); $this->_form->setSection('groups', _("Groups"), Horde::img('group.png'), false); - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - $group_list = $groups->listGroups(); - if ($group_list instanceof PEAR_Error) { - $GLOBALS['notification']->push($group_list); + try { + $groups = Horde_Group::singleton(); + $group_list = $groups->listGroups(); + } catch (Horde_Group_Exception $e) { + $GLOBALS['notification']->push($e); $group_list = array(); } diff --git a/framework/Group/Group.php b/framework/Group/Group.php deleted file mode 100644 index 50097e7fd..000000000 --- a/framework/Group/Group.php +++ /dev/null @@ -1,910 +0,0 @@ - - * @author Chuck Hagenbuch - * @package Horde_Group - */ -class Group { - - /** - * Group driver parameters - * - * @var array - */ - var $_params; - - /** - * Pointer to a DataTree instance to manage the different groups. - * - * @var DataTree - */ - var $_datatree; - - /** - * Cache of previously retrieved group objects. - * - * @var array - */ - var $_groupCache = array(); - - /** - * Id-name-map of already cached group objects. - * - * @var array - */ - var $_groupMap = array(); - - /** - * Id-name-hash of all existing groups. - * - * @var array - */ - var $_groupList; - - /** - * List of sub groups. - * - * @see listAllUsers() - * @var array - */ - var $_subGroups = array(); - - /** - * Cache of parent groups. - * - * This is an array with group IDs as keys and the integer group id of the - * direct parent as values. - * - * @see getGroupParent - * @var array - */ - var $_groupParents = array(); - - /** - * Cache of parent group trees. - * - * This is an array with group IDs as keys and id-name-hashes of all - * parents as values. - * - * @see getGroupParentList - * @var array - */ - var $_groupParentList = array(); - - /** - * Cache of parents tree. - * - * @see getGroupParents() - * @var array - */ - var $_parentTree = array(); - - /** - * Hash of groups of certain users. - * - * @see getGroupMemberShips() - * @var array - */ - var $_userGroups; - - /** - * Constructor. - */ - function Group($params) - { - $this->_params = $params; - $this->__wakeup(); - } - - /** - * Initializes the object. - * - * @throws Horde_Exception - */ - function __wakeup() - { - global $conf; - - if (empty($conf['datatree']['driver'])) { - throw new Horde_Exception('You must configure a DataTree backend to use Groups.'); - } - - $driver = $conf['datatree']['driver']; - $this->_datatree = &DataTree::singleton($driver, - array_merge(Horde::getDriverConfig('datatree', $driver), - array('group' => 'horde.groups'))); - - foreach (array_keys($this->_groupCache) as $name) { - $this->_groupCache[$name]->setGroupOb($this); - $this->_groupCache[$name]->setDataTree($this->_datatree); - } - } - - /** - * Returns a new group object. - * - * @param string $name The group's name. - * @param string $parent The group's parent's name. - * - * @return DataTreeObject_Group A new group object. - */ - function &newGroup($name, $parent = GROUP_ROOT) - { - if (empty($name)) { - return PEAR::raiseError(_("Group names must be non-empty")); - } - - if ($parent != GROUP_ROOT) { - $name = $this->getGroupName($parent) . ':' . DataTree::encodeName($name); - } - - $group = new DataTreeObject_Group($name); - $group->setGroupOb($this); - return $group; - } - - /** - * Returns a DataTreeObject_Group object corresponding to the named group, - * with the users and other data retrieved appropriately. - * - * @param string $name The name of the group to retrieve. - */ - function &getGroup($name) - { - if (!isset($this->_groupCache[$name])) { - $this->_groupCache[$name] = &$this->_datatree->getObject($name, 'DataTreeObject_Group'); - if (!is_a($this->_groupCache[$name], 'PEAR_Error')) { - $this->_groupCache[$name]->setGroupOb($this); - $this->_groupMap[$this->_groupCache[$name]->getId()] = $name; - } - } - - return $this->_groupCache[$name]; - } - - /** - * Returns a DataTreeObject_Group object corresponding to the given unique - * ID, with the users and other data retrieved appropriately. - * - * @param integer $cid The unique ID of the group to retrieve. - */ - function &getGroupById($cid) - { - if (isset($this->_groupMap[$cid])) { - $group = $this->_groupCache[$this->_groupMap[$cid]]; - } else { - $group = $this->_datatree->getObjectById($cid, 'DataTreeObject_Group'); - if (!is_a($group, 'PEAR_Error')) { - $group->setGroupOb($this); - $name = $group->getName(); - $this->_groupCache[$name] = &$group; - $this->_groupMap[$cid] = $name; - } - } - - return $group; - } - - /** - * Returns a globally unique ID for a group. - * - * @param DataTreeObject_Group $group The group. - * - * @return string A GUID referring to $group. - */ - function getGUID($group) - { - return 'horde:group:' . $this->getGroupId($group); - } - - /** - * Adds a group to the groups system. The group must first be created with - * Group::newGroup(), and have any initial users added to it, before this - * function is called. - * - * @param DataTreeObject_Group $group The new group object. - * - * @throws Horde_History_Exception - * @throws InvalidArgumentException - */ - function addGroup($group) - { - if (!is_a($group, 'DataTreeObject_Group')) { - return PEAR::raiseError('Groups must be DataTreeObject_Group objects or extend that class.'); - } - $result = $this->_datatree->add($group); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $id = $group->getId(); - $name = $group->getName(); - $this->_groupCache[$name] = &$group; - $this->_groupMap[$id] = $name; - if (isset($this->_groupList)) { - $this->_groupList[$id] = $name; - } - - /* Log the addition of the group in the history log. */ - $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'add'), true); - - return $result; - } - - /** - * Stores updated data - users, etc. - of a group to the backend system. - * - * @param DataTreeObject_Group $group The group to update. - * - * @throws Horde_History_Exception - * @throws InvalidArgumentException - */ - function updateGroup($group) - { - if (!is_a($group, 'DataTreeObject_Group')) { - return PEAR::raiseError('Groups must be DataTreeObject_Group objects or extend that class.'); - } - $result = $this->_datatree->updateData($group); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $this->_groupCache[$group->getName()] = &$group; - - /* Log the update of the group users on the history log. */ - $history = $GLOBALS['injector']->getInstance('Horde_History'); - $guid = $this->getGUID($group); - foreach ($group->getAuditLog() as $userId => $action) { - $history->log($guid, array('action' => $action, 'user' => $userId), true); - } - $group->clearAuditLog(); - - /* Log the group modification. */ - $history->log($guid, array('action' => 'modify'), true); - return $result; - } - - /** - * Removes a group from the groups system permanently. - * - * @param DataTreeObject_Group $group The group to remove. - * @param boolean $force Force to remove every child. - * - * @throws Horde_History_Exception - * @throws InvalidArgumentException - */ - function removeGroup($group, $force = false) - { - if (!is_a($group, 'DataTreeObject_Group')) { - return PEAR::raiseError('Groups must be DataTreeObject_Group objects or extend that class.'); - } - - $id = $group->getId(); - unset($this->_groupMap[$id]); - if (isset($this->_groupList)) { - unset($this->_groupList[$id]); - } - unset($this->_groupCache[$group->getName()]); - - $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'delete'), true); - - return $this->_datatree->remove($group, $force); - } - - /** - * Retrieves the name of a group. - * - * @param integer|DataTreeObject_Group $gid The id of the group or the - * group object to retrieve the - * name for. - * - * @return string The group's name. - */ - function getGroupName($gid) - { - if (is_a($gid, 'DataTreeObject_Group')) { - $gid = $gid->getId(); - } - - if (isset($this->_groupMap[$gid])) { - return $this->_groupMap[$gid]; - } - if (isset($this->_groupList[$gid])) { - return $this->_groupList[$gid]; - } - - return $this->_datatree->getName($gid); - } - - /** - * Strips all parent references off of the given group name. - * - * @param string $group Name of the group. - * - * @return The name of the group without parents. - */ - function getGroupShortName($group) - { - return $this->_datatree->getShortName($group); - } - - /** - * Retrieves the ID of a group. - * - * @param string|DataTreeObject_Group $group The group name or object to - * retrieve the ID for. - * - * @return integer The group's ID. - */ - function getGroupId($group) - { - if (is_a($group, 'DataTreeObject_Group')) { - $group = $group->getName(); - } - - $id = array_search($group, $this->_groupMap); - if ($id !== false) { - return $id; - } - if (isset($this->_groupList)) { - $id = array_search($group, $this->_groupList); - if ($id !== false) { - return $id; - } - } - - return $this->_datatree->getId($group); - } - - /** - * Check if a group exists in the system. - * - * @param string $group The group to check. - * - * @return boolean True if the group exists, false otherwise. - */ - function exists($group) - { - if (isset($this->_groupCache[$group]) || - (isset($this->_groupList) && - array_search($group, $this->_groupList) !== false)) { - return true; - } - - return $this->_datatree->exists($group); - } - - /** - * Returns a tree of the parents of a child group. - * - * @param integer $gid The id of the child group. - * - * @return array The group parents tree, with groupnames as the keys. - */ - function getGroupParents($gid) - { - if (!isset($this->_parentTree[$gid])) { - $name = $this->getGroupName($gid); - $parents = $this->_datatree->getParents($name); - if (is_a($parents, 'PEAR_Error')) { - return $parents; - } - $this->_parentTree[$gid] = $parents; - } - - return $this->_parentTree[$gid]; - } - - /** - * Returns the single parent ID of the given group. - * - * @param integer $gid The DataTree ID of the child group. - * - * @return integer The parent of the given group. - */ - function getGroupParent($gid) - { - if (!isset($this->_groupParents[$gid])) { - $parent = $this->_datatree->getParentById($gid); - if (is_a($parent, 'PEAR_Error')) { - return $parent; - } - $this->_groupParents[$gid] = $parent; - } - - return $this->_groupParents[$gid]; - } - - /** - * Returns a flat list of the parents of a child group - * - * @param integer $gid The id of the group. - * - * @return array A flat list of all of the parents of $group, hashed in - * $id => $name format. - */ - function getGroupParentList($gid) - { - if (!isset($this->_groupParentList[$gid])) { - $parents = $this->_datatree->getParentList($gid); - if (is_a($parents, 'PEAR_Error')) { - return $parents; - } - $this->_groupParentList[$gid] = $parents; - } - - return $this->_groupParentList[$gid]; - } - - /** - * Returns a list of all groups, in the format id => groupname. - * - * @param boolean $refresh If true, the cached value is ignored and the - * group list is refreshed from the group backend. - * - * @return array ID => groupname hash. - */ - function listGroups($refresh = false) - { - if ($refresh || !isset($this->_groupList)) { - $this->_groupList = $this->_datatree->get(DATATREE_FORMAT_FLAT, GROUP_ROOT, true); - unset($this->_groupList[GROUP_ROOT]); - } - - return $this->_groupList; - } - - /** - * Get a list of every user that is a part of this group ONLY. - * - * @param integer $gid The ID of the group. - * - * @return array The user list. - */ - function listUsers($gid) - { - $groupOb = &$this->getGroupById($gid); - if (is_a($groupOb, 'PEAR_Error')) { - return $groupOb; - } - - if (!isset($groupOb->data['users']) || - !is_array($groupOb->data['users'])) { - return array(); - } - - return array_keys($groupOb->data['users']); - } - - /** - * Get a list of every user that is part of the specified group - * and any of its subgroups. - * - * @param integer $group The ID of the parent group. - * - * @return array The complete user list. - */ - function listAllUsers($gid) - { - if (!isset($this->_subGroups[$gid])) { - // Get a list of every group that is a sub-group of $group. - $groups = $this->_datatree->get(DATATREE_FORMAT_FLAT, $this->getGroupName($gid), true); - if (is_a($groups, 'PEAR_Error')) { - return $groups; - } - $this->_subGroups[$gid] = array_keys($groups); - } - - $users = array(); - foreach ($this->_subGroups[$gid] as $groupId) { - $users = array_merge($users, $this->listUsers($groupId)); - } - return array_values(array_flip(array_flip($users))); - } - - /** - * Get a list of every group that $user is in. - * - * @param string $user The user to get groups for. - * @param boolean $parentGroups Also return the parents of any groups? - * - * @return array An array of all groups the user is in. - */ - function getGroupMemberships($user, $parentGroups = false) - { - if (!isset($this->_userGroups[$user])) { - $criteria = array( - 'AND' => array( - array('field' => 'name', 'op' => '=', 'test' => 'user'), - array('field' => 'key', 'op' => '=', 'test' => $user))); - $groups = $this->_datatree->getByAttributes($criteria); - - if (is_a($groups, 'PEAR_Error')) { - return $groups; - } - - if ($parentGroups) { - foreach ($groups as $id => $g) { - $parents = $this->_datatree->getParentList($id); - if (is_a($parents, 'PEAR_Error')) { - return $parents; - } - $groups += $parents; - } - } - - $this->_userGroups[$user] = $groups; - } - - return $this->_userGroups[$user]; - } - - /** - * Say if a user is a member of a group or not. - * - * @param string $user The name of the user. - * @param integer $gid The ID of the group. - * @param boolean $subgroups Return true if the user is in any subgroups - * of group with ID $gid, also. - * - * @return boolean - */ - function userIsInGroup($user, $gid, $subgroups = true) - { - if (!$this->exists($this->getGroupName($gid))) { - return false; - } elseif ($subgroups) { - $groups = $this->getGroupMemberships($user, true); - if (is_a($groups, 'PEAR_Error')) { - Horde::logMessage($groups, 'ERR'); - return false; - } - - return !empty($groups[$gid]); - } else { - $users = $this->listUsers($gid); - if (is_a($users, 'PEAR_Error')) { - Horde::logMessage($users, 'ERR'); - return false; - } - return in_array($user, $users); - } - } - - /** - * Returns the nesting level of the given group. 0 is returned for any - * object directly below GROUP_ROOT. - * - * @param integer $gid The DataTree ID of the group. - * - * @return The DataTree level of the group. - */ - function getLevel($gid) - { - $name = $this->getGroupName($gid); - return substr_count($name, ':'); - } - - /** - * Stores the object in the session cache. - */ - function shutdown() - { - $session = new Horde_SessionObjects(); - $session->overwrite('horde_group', $this, false); - } - - /** - * Returns the properties that need to be serialized. - * - * @return array List of serializable properties. - */ - function __sleep() - { - $properties = get_object_vars($this); - unset($properties['_datatree']); - $properties = array_keys($properties); - return $properties; - } - - /** - * Attempts to return a concrete Group instance based on $driver. - * - * @param mixed $driver The type of concrete Group subclass to return. - * @param array $params A hash containing any additional configuration or - * connection parameters a subclass might need. - * - * @return Group The newly created concrete Group instance, or a - * PEAR_Error object on an error. - */ - public static function factory($driver = '', $params = null) - { - if (is_null($params)) { - $params = Horde::getDriverConfig('group', $driver); - } - - $class = Group::_loadDriver($driver); - if (class_exists($class)) { - $group = new $class($params); - } else { - $group = PEAR::raiseError('Class definition of ' . $class . ' not found.'); - } - - return $group; - } - - /** - * Attempts to return a reference to a concrete Group instance. - * It will only create a new instance if no Group instance - * currently exists. - * - * This method must be invoked as: $var = &Group::singleton() - * - * @return Group The concrete Group reference, or false on an error. - */ - public static function singleton() - { - static $group; - - if (isset($group)) { - return $group; - } - - $group_driver = null; - $group_params = null; - $auth = $GLOBALS['injector']->getInstance('Horde_Auth')->getOb(); - if ($auth->hasCapability('groups')) { - $group_driver = $auth->getDriver(); - $group_params = $auth; - } elseif (!empty($GLOBALS['conf']['group']['driver']) && - $GLOBALS['conf']['group']['driver'] != 'datatree') { - $group_driver = $GLOBALS['conf']['group']['driver']; - $group_params = Horde::getDriverConfig('group', $group_driver); - } - - Group::_loadDriver($group_driver); - - $group = null; - if (!empty($GLOBALS['conf']['group']['cache'])) { - $session = new Horde_SessionObjects(); - $group = $session->query('horde_group'); - } - - if (!$group) { - $group = Group::factory($group_driver, $group_params); - } - - if (!empty($GLOBALS['conf']['group']['cache'])) { - register_shutdown_function(array(&$group, 'shutdown')); - } - - return $group; - } - - protected static function _loadDriver($driver) - { - if (!$driver) { - $class = 'Group'; - } else { - $driver = basename($driver); - $class = 'Group_' . $driver; - if (!class_exists($class)) { - include 'Horde/Group/' . $driver . '.php'; - } - } - - return $class; - } - -} - -/** - * Extension of the DataTreeObject class for storing Group information - * in the Categories driver. If you want to store specialized Group - * information, you should extend this class instead of extending - * DataTreeObject directly. - * - * @author Chuck Hagenbuch - * @package Horde_Group - */ -class DataTreeObject_Group extends DataTreeObject { - - /** - * The Group object which this group is associated with - needed - * for updating data in the backend to make changes stick, etc. - * - * @var Group - */ - var $_groupOb; - - /** - * This variable caches the users added or removed from the group - * for History logging of user-groups relationship. - * - * @var array - */ - var $_auditLog = array(); - - /** - * The DataTreeObject_Group constructor. Just makes sure to call - * the parent constructor so that the group's name is set - * properly. - * - * @param string $name The name of the group. - */ - function DataTreeObject_Group($name) - { - parent::DataTreeObject($name); - } - - /** - * Returns the properties that need to be serialized. - * - * @return array List of serializable properties. - */ - function __sleep() - { - $properties = get_object_vars($this); - unset($properties['datatree'], $properties['_groupOb']); - $properties = array_keys($properties); - return $properties; - } - - /** - * Associates a Group object with this group. - * - * @param Group $groupOb The Group object. - */ - function setGroupOb(&$groupOb) - { - $this->_groupOb = &$groupOb; - } - - /** - * Fetch the ID of this group - * - * @return string The group's ID - */ - function getId() - { - return $this->_groupOb->getGroupId($this); - } - - /** - * Save any changes to this object to the backend permanently. - */ - function save() - { - return $this->_groupOb->updateGroup($this); - - } - - /** - * Adds a user to this group, and makes sure that the backend is - * updated as well. - * - * @param string $username The user to add. - */ - function addUser($username, $update = true) - { - $this->data['users'][$username] = 1; - $this->_auditLog[$username] = 'addUser'; - if ($update && $this->_groupOb->exists($this->getName())) { - return $this->save(); - } - } - - /** - * Removes a user from this group, and makes sure that the backend - * is updated as well. - * - * @param string $username The user to remove. - */ - function removeUser($username, $update = true) - { - unset($this->data['users'][$username]); - $this->_auditLog[$username] = 'deleteUser'; - if ($update) { - return $this->save(); - } - } - - /** - * Get a list of every user that is a part of this group - * (and only this group) - * - * @return array The user list - */ - function listUsers() - { - return $this->_groupOb->listUsers($this->getId()); - } - - /** - * Get a list of every user that is a part of this group and - * any of it's subgroups - * - * @return array The complete user list - */ - function listAllUsers() - { - return $this->_groupOb->listAllUsers($this->getId()); - } - - /** - * Get all the users recently added or removed from the group. - */ - function getAuditLog() - { - return $this->_auditLog; - } - - /** - * Clears the audit log. To be called after group update. - */ - function clearAuditLog() - { - $this->_auditLog = array(); - } - - /** - * Map this object's attributes from the data array into a format - * that we can store in the attributes storage backend. - * - * @return array The attributes array. - */ - function _toAttributes() - { - // Default to no attributes. - $attributes = array(); - - // Loop through all users, if any. - if (isset($this->data['users']) && is_array($this->data['users']) && count($this->data['users'])) { - foreach ($this->data['users'] as $user => $active) { - $attributes[] = array('name' => 'user', - 'key' => $user, - 'value' => $active); - } - } - $attributes[] = array('name' => 'email', - 'key' => '', - 'value' => $this->get('email')); - - return $attributes; - } - - /** - * Take in a list of attributes from the backend and map it to our - * internal data array. - * - * @param array $attributes The list of attributes from the - * backend (attribute name, key, and value). - */ - function _fromAttributes($attributes) - { - // Initialize data array. - $this->data['users'] = array(); - - foreach ($attributes as $attr) { - if ($attr['name'] == 'user') { - $this->data['users'][$attr['key']] = $attr['value']; - } else { - $this->data[$attr['name']] = $attr['value']; - } - } - } - -} diff --git a/framework/Group/Group/contactlists.php b/framework/Group/Group/contactlists.php deleted file mode 100644 index 52ea400d1..000000000 --- a/framework/Group/Group/contactlists.php +++ /dev/null @@ -1,721 +0,0 @@ - - * @package Horde_Group - */ -class Group_contactlists extends Group { - - /** - * A cache object - * - * @var Horde_Cache object - */ - var $_cache = null; - - /** - * Handles for the database connections. Need one for each possible source. - * - * @var DB - */ - var $_db = array(); - - /** - * Local copy of available address book sources that the group driver can - * use. - * - * @var array of Turba's cfgSource style entries. - */ - var $_sources = array(); - - /** - * Local cache of retreived group entries from Turba storage. - * - * @var unknown_type - */ - var $_listEntries = array(); - - /** - * Constructor. - */ - function Group_contactlists($params) - { - // Get a list of all available Turba sources - $turba_sources = Horde::loadConfiguration('sources.php', - 'cfgSources', 'turba'); - - // We only support sql type sources. - foreach ($turba_sources as $key => $source) { - if ($source['type'] == 'sql') { - $this->_sources[$key] = $source; - } - } - - $this->_cache = $GLOBALS['injector']->getInstance('Horde_Cache'); - } - - /** - * Initializes the object. - */ - function __wakeup() - { - } - - /** - * Returns the properties that need to be serialized. - * - * @return array List of serializable properties. - */ - function __sleep() - { - } - - /** - * Stores the object in the session cache. - */ - function shutdown() - { - } - - /** - * Returns a new group object. - * - * @param string $name The group's name. - * @param string $parent The group's parent's name. - * - * @return PEAR_Error This functionality is not supported in this driver. - */ - function newGroup($name, $parent = GROUP_ROOT) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Returns a Group object corresponding to the named group, - * with the users and other data retrieved appropriately. - * - * This is deprecated. Use getGroupById instead. - * - * @param string $name The name of the group to retrieve. - */ - function getGroup($name) - { - return PEAR::raiseError(_("Deprecated. Use getGroupById() instead.")); - } - - /** - * Returns a ContactListObject_Group object corresponding to the given unique - * ID, with the users and other data retrieved appropriately. - * - * @param integer $cid The unique ID of the group to retrieve. - */ - function getGroupById($gid) - { - - if (!empty($this->_groupCache[$gid])) { - return $this->_groupCache[$gid]; - } - list($source, $id) = explode(':', $gid); - $entry = $this->_retrieveListEntry($gid); - if (is_a($entry, 'PEAR_Error')) { - return $entry; - } elseif (empty($entry)) { - return PEAR::raiseError($gid . ' does not exist'); - } - - $users = $this->_getAllMembers($gid); - if (is_a($users, 'PEAR_Error')) { - return $users; - } - - $group = new ContactListObject_Group($entry[$this->_sources[$source]['map'][$this->_sources[$source]['list_name_field']]]); - $group->id = $gid; - $group->data['email'] = $entry[$this->_sources[$source]['map']['email']]; - if (!empty($users)) { - $group->data['users'] = array_flip($users); - } - - $group->setGroupOb($this); - $this->_groupCache[$gid] = $group; - - return $group; - } - - /** - * Adds a group to the groups system. The group must first be created with - * Group::newGroup(), and have any initial users added to it, before this - * function is called. - * - * @param ContactListObjectObject_Group $group The new group object. - * - * @return PEAR_Error - unsupported - */ - function addGroup($group) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Stores updated data - users, etc. - of a group to the backend system. - * - * @param ContactListObject_Group $group The group to update. - */ - function updateGroup($group) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Removes a group from the groups system permanently. - * - * @param ContactListObject_Group $group The group to remove. - * @param boolean $force Force to remove every child. - * - * @return PEAR_Error - unsupported. - */ - function removeGroup($group, $force = false) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Retrieves the name of a group. - * - * @param integer|ContactListObject_Group $gid The id of the group or the - * group object to retrieve the - * name for. - * - * @return string The group's name. - */ - function getGroupName($gid) - { - static $beenHere; - - if (strpos($gid, ':') === false) { - return PEAR::raiseError(sprintf(_("Group %s not found."), $gid)); - } - - if (is_a($gid, 'ContactListObject_Group')) { - $gid = $gid->getId(); - } - if (!empty($this->_listEntries[$gid])) { - list($source, $id) = explode(':', $gid); - $beenHere = false; - return $this->_listEntries[$gid][$this->_sources[$source]['map'][$this->_sources[$source]['list_name_field']]]; - } - - $result = $this->_retrieveListEntry($gid); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - // We should have the information cached now, try again..but protect - // against anything nasty... - if (!$beenHere) { - $beenHere = true; - return $this->getGroupName($gid); - } - - return PEAR::raiseError(sprintf(_("Group %s not found."), $gid)); - } - - /** - * Strips all parent references off of the given group name. - * - * Not used in this driver...group display names are ONLY for display. - * - * @param string $group Name of the group. - * - * @return The name of the group without parents. - */ - function getGroupShortName($group) - { - return $group; - } - - /** - * Retrieves the ID of a group, given the group object. - * Here for BC. Kinda silly, since if we have the object, we can just call - * getId() ourselves. - * - * @param ContactListObject_Group $group The group object to retrieve the - * ID for. - * - * @return integer The group's ID. - */ - function getGroupId($group) - { - if (is_a($group, 'ContactListObject_Group')) { - return $group->getId(); - } - - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Check if a group exists in the system. - * - * This must either be a noop or we need to somehow "uniqueify" the - * list's display name? - * - * @param string $group The group name to check. - * - * @return boolean True if the group exists, false otherwise. - */ - function exists($group) - { - return true; - } - - /** - * Returns a tree of the parents of a child group. - * - * @param integer $gid The id of the child group. - * - * @return array The group parents tree, with groupnames as the keys. - */ - function getGroupParents($gid) - { - return array(); - } - - - /** - * Returns the single parent ID of the given group. - * - * @param integer $gid The ID of the child group. - * - * @return integer The parent of the given group. - */ - function getGroupParent($gid) - { - return GROUP_ROOT; - } - - /** - * Returns a flat list of the parents of a child group - * - * @param integer $gid The id of the group. - * - * @return array A flat list of all of the parents of $group, hashed in - * $id => $name format. - */ - function getGroupParentList($gid) - { - return array(); - } - - /** - * Returns a list of all groups, in the format id => groupname. - * The groups returned represent only the groups visible to the current user - * only. - * - * @param boolean $refresh If true, the cached value is ignored and the - * group list is refreshed from the group backend. - * - * @return array ID => groupname hash. - */ - function listGroups($refresh = false) - { - if (isset($this->_groupList) && !$refresh) { - return $this->_groupList; - } - - // First, make sure we are connected to all sources - $this->_connect(); - - $groups = array(); - $owners = array(); - foreach ($this->_sources as $key => $source) { - if ($source['use_shares']) { - if (empty($contact_shares)) { - $scope = $GLOBALS['registry']->hasInterface('contacts'); - $shares = $GLOBALS['injector']->getInstance('Horde_Share')->getScope($scope); - $this->_contact_shares = $shares->listShares(Horde_Auth::getAuth(), Horde_Perms::SHOW, Horde_Auth::getAuth()); - } - // Contruct a list of owner ids to use - foreach ($this->_contact_shares as $id => $share) { - $params = @unserialize($share->get('params')); - if ($params['source'] == $key) { - $owners[] = $params['name']; - } - } - } else { - $owners = array(Horde_Auth::getAuth()); - } - $owner_ids = array(); - foreach ($owners as $owner) { - $owner_ids[] = $this->_db[$key]->quote($owner); - } - $sql = 'SELECT ' . $source['map']['__key'] . ', ' . $source['map'][$source['list_name_field']] - . ' FROM ' . $source['params']['table'] . ' WHERE ' - . $source['map']['__type'] . ' = \'Group\' AND ' - . $source['map']['__owner'] . ' IN (' . implode(',', $owner_ids ) . ')'; - - $results = $this->_db[$key]->getAssoc($sql); - foreach ($results as $id => $name) { - $groups[$key . ':' . $id] = $name; - } - } - $this->_groupList = $groups; - - return $this->_groupList; - } - - /** - * Get a list of every user that is part of the specified group - * and any of its subgroups. - * - * @param integer $group The ID of the parent group. - * - * @return array The complete user list. - */ - function listAllUsers($gid) - { - $members = $this->_getAllMembers($gid, true); - if (is_a($members, 'PEAR_Error')) { - return $members; - } - - return array_values($members); - } - - /** - * Returns a hash representing the list entry. Items are keyed by the - * backend specific keys. - * - * @param string $gid The group id - * @return array | PEAR_Error - */ - function _retrieveListEntry($gid) - { - if (!empty($this->_listEntries[$gid])) { - return $this->_listEntries[$gid]; - } - - list($source, $id) = explode(':', $gid); - if (empty($this->_sources[$source])) { - return array(); - } - - $this->_connect($source); - $sql = 'SELECT ' . $this->_sources[$source]['map']['__members'] . ',' - . $this->_sources[$source]['map']['email'] . ',' - . $this->_sources[$source]['map'][$this->_sources[$source]['list_name_field']] - . ' from ' . $this->_sources[$source]['params']['table'] . ' WHERE ' - . $this->_sources[$source]['map']['__key'] . ' = ' . $this->_db[$source]->quote($id); - - $results = $this->_db[$source]->getRow($sql,array(), DB_FETCHMODE_ASSOC); - if (is_a($results, 'PEAR_Error')) { - Horde::logMessage($results, 'ERR'); - } - $this->_listEntries[$gid] = $results; - - return $results; - - } - - /** - * TODO - */ - function _getAllMembers($gid, $subGroups = false) - { - if (empty($gid) || strpos($gid, ':') === false) { - return PEAR::raiseError(sprintf(_("Unsupported group id: %s"), $gid)); - } - - list($source, $id) = explode(':', $gid); - $entry = $this->_retrieveListEntry($gid); - if (is_a($entry, 'PEAR_Error')) { - return $entry; - } - $members = @unserialize($entry[$this->_sources[$source]['map']['__members']]); - $users = array(); - - // TODO: optimize this to only query each table once - foreach ($members as $member) { - - // Is this member from the same source or a different one? - if (strpos($member, ':') !== false) { - list($newSource, $uid) = explode(':', $member); - if (!empty($this->_contact_shares[$newSource])) { - $params = @unserialize($this->_contact_shares[$newSource]->get('params')); - $newSource = $params['source']; - $member = $uid; - $this->_connect($newSource); - } elseif (empty($this->_sources[$newSource])) { - // Last chance, it's not in one of our non-share sources - continue; - } - } else { - // Same source - $newSource = $source; - } - - $sql = 'SELECT ' . $this->_sources[$newSource]['map']['email'] - . ', ' . $this->_sources[$newSource]['map']['__type'] - . ' FROM ' . $this->_sources[$newSource]['params']['table'] - . ' WHERE ' . $this->_sources[$newSource]['map']['__key'] - . ' = ' . $this->_db[$newSource]->quote($member); - - $results = $this->_db[$newSource]->getRow($sql); - if (is_a($results, 'PEAR_Error')) { - Horde::logMessage($results, 'ERR'); - return $results; - } - - // Sub-Lists are treated as sub groups the best that we can... - if ($subGroups && $results[1] == 'Group') { - $this->_subGroups[$gid] = $newSource . ':' . $member; - $users = array_merge($users, $this->_getAllMembers($newSource . ':' . $member)); - } - if (strlen($results[0])) { - // use a key to dump dups - $users[$results[0]] = $results[0]; - } - } - - return $users; - } - - /** - * Returns ALL contact lists present in ALL sources that this driver knows - * about. - * - */ - function _listAllLists() - { - // Clear the cache - we will rebuild it. - $this->_listEntries = array(); - - foreach ($this->_sources as $key => $source) { - $this->_connect($key); - $sql = 'SELECT ' . $source['map']['__key'] . ',' - . $source['map']['__members'] . ',' - . $source['map']['email'] . ',' - . $source['map'][$source['list_name_field']] - . ' FROM ' . $source['params']['table'] . ' WHERE ' - . $source['map']['__type'] . ' = \'Group\''; - - $results = $this->_db[$key]->query($sql); - if (is_a($results, 'PEAR_Error')) { - return $results; - } - while ($row = $results->fetchRow(DB_FETCHMODE_ASSOC)) { - $this->_listEntries[$key . ':' . $row[$source['map']['__key']]] = $row; - } - } - - return $this->_listEntries; - } - - /** - * Get a list of every group that $user is in. - * - * @param string $user The user to get groups for. - * @param boolean $parentGroups Also return the parents of any groups? - * - * @return array An array of all groups the user is in. - */ - function getGroupMemberships($user, $parentGroups = false) - { - if (($memberships = $this->_cache->get('Group_contactlists_memberships' . md5($user))) !== false) { - return unserialize($memberships); - } - $lists = $this->_listAllLists(); - $memberships = array(); - foreach (array_keys($lists) as $list) { - $members = $this->_getAllMembers($list, $parentGroups); - if (!empty($members[$user])) { - $memberships[] = $list; - } - } - - $this->_cache->set('Group_contactlists_memberships' . md5($user), serialize($memberships)); - return $memberships; - - } - - /** - * Say if a user is a member of a group or not. - * - * @param string $user The name of the user. - * @param integer $gid The ID of the group. - * @param boolean $subgroups Return true if the user is in any subgroups - * of group with ID $gid, also. - * - * @return boolean - */ - function userIsInGroup($user, $gid, $subgroups = true) - { - if (isset($_SESSION['horde']['groups']['i'][$user][$subgroups][$gid])) { - return $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid]; - } - - $users = $this->_getAllMembers($gid, $subgroups); - if (is_a($users, 'PEAR_Error')) { - Horde::logMessage($users, 'ERR'); - return false; - } - $result = !empty($users[$user]); - $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid] = (bool)$result; - return (bool)$result; - } - - /** - * Attempts to open a persistent connection to the sql server. - * - * @return boolean True on success. - * @throws Horde_Exception - */ - function _connect($source = null) - { - if (!is_null($source) && !empty($this->_db[$source])) { - return true; - } - /* Connect to the sql server using the supplied parameters. */ - require_once 'DB.php'; - - if (is_null($source)) { - $sources = array_keys($this->_sources); - } else { - $sources = array($source); - } - - foreach ($sources as $source) { - if (empty($this->_db[$source])) { - $this->_db[$source] = DB::connect($this->_sources[$source]['params'], - array('persistent' => !empty($this->_sources[$source]['params']['persistent']))); - if (is_a($this->_db[$source], 'PEAR_Error')) { - throw new Horde_Exception_Prior($this->_db[$source]); - } - - /* Set DB portability options. */ - switch ($this->_db[$source]->phptype) { - case 'mssql': - $this->_db[$source]->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); - break; - default: - $this->_db[$source]->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); - } - } - } - - return true; - } - -} - -/** - * Extension of the DataTreeObject_Group class for storing Group information. - * - * @author Michael J. Rubinsky - * @package Horde_Group - */ -class ContactListObject_Group extends DataTreeObject_Group { - - /** - * The unique name of this object. - * These names have the same requirements as other object names - they must - * be unique, etc. - * - * @var string - */ - var $name; - - /** - * The unique name of this object. - * These names have the same requirements as other object names - they must - * be unique, etc. - * - * @var integer - */ - var $id; - - /** - * Key-value hash that will be serialized. - * - * @see getData() - * @var array - */ - var $data = array(); - - /** - * Constructor. - * - * @param string $name The name of the group. - */ - function ContactListObject_Group($name) - { - $this->name = $name; - } - - /** - * Gets the ID of this object. - * - * @return string The object's ID. - */ - function getId() - { - return $this->id; - } - - /** - * Gets the name of this object. - * - * @return string The object name. - */ - function getName() - { - return $this->name; - } - - /** - * 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. - */ - function get($attribute) - { - return isset($this->data[$attribute]) - ? $this->data[$attribute] - : null; - } - - /** - * Sets one of the attributes of the object. - * - * @param string $attribute The attribute to set. - * @param mixed $value The value for $attribute. - */ - function set($attribute, $value) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Save group - */ - function save() - { - return PEAR::raiseError(_("Unsupported")); - } - - function removeUser($username, $update = true) - { - return PEAR::raiseError(_("Unsupported")); - } - function addUser($username, $update = true) - { - return PEAR::raiseError(_("Unsupported")); - } -} diff --git a/framework/Group/Group/hooks.php b/framework/Group/Group/hooks.php deleted file mode 100644 index afb7b876c..000000000 --- a/framework/Group/Group/hooks.php +++ /dev/null @@ -1,79 +0,0 @@ - - * @package Horde_Group - */ -class Group_hooks extends Group { - - var $_hookFunction = false; - - /** - * Constructor. - */ - function Group_hooks($params) - { - parent::Group($params); - Horde::loadConfiguration('hooks.php', null, 'horde'); - $this->_hookFunction = function_exists('_group_hook'); - } - - /** - * Get a list of every group that $user is in. - * - * @param string $user The user to get groups for. - * @param boolean $parentGroups Also return the parents of any groups? - * - * @return array An array of all groups the user is in. - */ - function getGroupMemberships($user, $parentGroups = false) - { - $memberships = parent::getGroupMemberships($user, $parentGroups); - if (!$this->_hookFunction) { - return $memberships; - } - - $groups = $this->listGroups(); - foreach ($groups as $gid => $groupName) { - if (empty($memberships[$gid]) && _group_hook($groupName, $user)) { - $memberships += array($gid => $groupName); - } - - if ($parentGroups) { - $parents = $this->getGroupParentList($gid); - if (is_a($parents, 'PEAR_Error')) { - return $parents; - } - - $memberships += $parents; - } - } - - return $memberships; - } - - /** - * Say if a user is a member of a group or not. - * - * @param string $user The name of the user. - * @param integer $gid The ID of the group. - * @param boolean $subgroups Return true if the user is in any subgroups - * of $group, also. - * - * @return boolean - */ - function userIsInGroup($user, $gid, $subgroups = true) - { - $inGroup = ($this->_hookFunction && _group_hook($this->getGroupName($gid), $user)); - return ($inGroup || parent::userIsInGroup($user, $gid, $subgroups)); - } - -} diff --git a/framework/Group/Group/kolab.php b/framework/Group/Group/kolab.php deleted file mode 100644 index d901e20fc..000000000 --- a/framework/Group/Group/kolab.php +++ /dev/null @@ -1,494 +0,0 @@ - - * @package Horde_Group - */ -class Group_kolab extends Group_ldap { - - /** - * A marker for fatal errors - */ - var $_error; - - /** - * Constructor. - */ - function Group_kolab($params) - { - if (!function_exists('ldap_connect')) { - $this->_error = PEAR::raiseError(_("The Kolab group driver requires LDAP support.")); - } - - $this->_params = array(); - $this->_params['hostspec'] = $GLOBALS['conf']['kolab']['ldap']['server']; - $this->_params['basedn'] = $GLOBALS['conf']['kolab']['ldap']['basedn']; - $this->_params['binddn'] = $GLOBALS['conf']['kolab']['ldap']['phpdn']; - $this->_params['password'] = $GLOBALS['conf']['kolab']['ldap']['phppw']; - $this->_params['version'] = 3; - $this->_params['gid'] = 'cn'; - $this->_params['memberuid'] = 'member'; - $this->_params['attrisdn'] = true; - $this->_params['filter_type'] = 'objectclass'; - $this->_params['objectclass'] = 'kolabGroupOfNames'; - $this->_params['newgroup_objectclass'] = 'kolabGroupOfNames'; - - $this->_filter = 'objectclass=' . $this->_params['objectclass']; - - $this->__wakeup(); - } - - /** - * Initializes the object. - */ - function __wakeup() - { - foreach (array_keys($this->_groupCache) as $name) { - $this->_groupCache[$name]->setGroupOb($this); - } - } - - /** - * Returns the properties that need to be serialized. - * - * @return array List of serializable properties. - */ - function __sleep() - { - $properties = get_object_vars($this); - unset($properties['_datatree'], $properties['_ds']); - $properties = array_keys($properties); - return $properties; - } - - - /** - * Returns a new group object. - * - * @param string $name The group's name. - * @param string $parent The group's parent's name. - * - * @return Kolab_Group A new group object. - */ - function &newGroup($name) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Adds a group to the groups system. The group must first be created with - * Group::newGroup(), and have any initial users added to it, before this - * function is called. - * - * @param Kolab_Group $group The new group object. - */ - function addGroup($group) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Stores updated data - users, etc. - of a group to the backend system. - * - * @param Kolab_Group $group The group to update. - */ - function updateGroup($group) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Removes a group from the groups system permanently. - * - * @param Kolab_Group $group The group to remove. - * @param boolean $force Force to remove every child. - */ - function removeGroup($group, $force = false) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Return a Kolab_Group object corresponding to the given dn, with the - * users and other data retrieved appropriately. - * - * @param string $dn The dn of the group to retrieve. - * - * @return Kolab_Group The requested group. - */ - function &getGroupById($dn) - { - static $cache = array(); - - if (!isset($cache[$dn])) { - - if (is_a($this->_error, 'PEAR_Error')) { - return $this->_error; - } - - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $search = @ldap_search($this->_ds, $dn, $this->_filter); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - return PEAR::raiseError(_("Empty result")); - } - - $attributes = array(); - for ($i = 0; $i < $result[0]['count']; $i++) { - if ($result[0][$result[0][$i]]['count'] > 1) { - $attributes[$result[0][$i]] = array(); - for ($j = 0; $j < $result[0][$result[0][$i]]['count']; $j++) { - $attributes[$result[0][$i]][] = $result[0][$result[0][$i]][$j]; - } - } else { - $attributes[$result[0][$i]] = $result[0][$result[0][$i]][0]; - } - } - $attributes['dn'] = $result[0]['dn']; - - $group = new Kolab_Group($this->getGroupName($dn)); - $group->_fromAttributes($attributes); - $group->setGroupOb($this); - $cache[$dn] = $group; - } - - return $cache[$dn]; - } - - - /** - * Retrieve the ID of the given group. - * - * NOTE: If given a group name, this function can be unreliable if more - * than one group exists with the same name. - * - * @param mixed $group LDAP_Group object, or a group name (string) - * - * @return string The group's ID. - */ - function getGroupId($group) - { - static $cache = array(); - - if (is_a($group, 'Kolab_Group')) { - return $group->getDn(); - } - - if (!isset($cache[$group])) { - - if (is_a($this->_error, 'PEAR_Error')) { - return $this->_error; - } - - $this->_connect(); - $search = @ldap_search($this->_ds, $this->_params['basedn'], - $this->_params['gid'] . '=' . $group, - array($this->_params['gid'])); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - return PEAR::raiseError(_("Empty result")); - } - $cache[$group] = $result[0]['dn']; - } - - return $cache[$group]; - } - - /** - * Get a list of the parents of a child group. - * - * @param string $dn The fully qualified group dn - * - * @return array Nested array of parents - */ - function getGroupParents($dn) - { - return array(); - } - - /** - * Get the parent of the given group. - * - * @param string $dn The dn of the child group. - * - * @return string The dn of the parent group. - */ - function getGroupParent($dn) - { - return null; - } - - /** - * Get a list of parents all the way up to the root object for the given - * group. - * - * @param string $dn The dn of the group. - * - * @return array A flat list of all of the parents of the given group, - * hashed in $dn => $name format. - */ - function getGroupParentList($dn) - { - return array(); - } - - /** - * Tries to find a DN for a given kolab mail address. - * - * @param string $mail The mail address to search for. - * - * @return string The corresponding dn or false. - */ - function dnForMail($mail) - { - $filter = '(&(objectclass=kolabInetOrgPerson)(mail=' . Horde_Ldap::quote($mail) . '))'; - $search = @ldap_search($this->_ds, $this->_params['basedn'], $filter); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - $dn = @ldap_first_entry($this->_ds, $search); - if ($dn) { - return ldap_get_dn($this->_ds, $dn); - } - return PEAR::raiseError(sprintf(_("Error searching for user with the email address \"%s\"!"), - $mail)); - } - - /** - * Get a list of every group that the given user is a member of. - * - * @param string $user The user to get groups for. - * @param boolean $parentGroups Also return the parents of any groups? - * - * @return array An array of all groups the user is in. - */ - function getGroupMemberships($user, $parentGroups = false) - { - static $cache = array(); - - if (empty($cache[$user])) { - - if (is_a($this->_error, 'PEAR_Error')) { - return $this->_error; - } - - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $dn = $this->dnForMail($user); - if (is_a($dn, 'PEAR_Error')) { - return $dn; - } - - // Set up search filter - $filter = '(' . $this->_params['memberuid'] . '=' . $dn . ')'; - - // Perform search - $search = @ldap_search($this->_ds, $this->_params['basedn'], $filter); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - return array(); - } - - $groups = array(); - $current_charset = Horde_Nls::getCharset(); - for ($i = 0; $i < $result['count']; $i++) { - $utf8_dn = Horde_String::convertCharset($result[$i]['dn'], 'UTF-8', $current_charset); - $groups[$utf8_dn] = $this->getGroupName($utf8_dn); - } - - $cache[$user] = $groups; - } - - return $cache[$user]; - } - -} - -/** - * - * - * @author Ben Chavet - * @package Horde_Group - */ -class Kolab_Group extends LDAP_Group { - - /** - * Constructor. - * - * @param string $name The name of this group. - * @param string $parent The dn of the parent of this group. - */ - function Kolab_Group($name, $parent = null) - { - $this->setName($name); - } - - /** - * Fetch the ID of this group - * - * @return string The group's ID - */ - function getId() - { - return $this->getDn(); - } - - /** - * Save any changes to this object to the backend permanently. - */ - function save() - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Adds a user to this group, and makes sure that the backend is - * updated as well. - * - * @param string $username The user to add. - */ - function addUser($username, $update = true) - { - return PEAR::raiseError(_("Unsupported")); - } - - - /** - * Removes a user from this group, and makes sure that the backend - * is updated as well. - * - * @param string $username The user to remove. - */ - function removeUser($username, $update = true) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Get all the users recently added or removed from the group. - */ - function getAuditLog() - { - return array(); - } - - /** - * Clears the audit log. To be called after group update. - */ - function clearAuditLog() - { - } - - /** - * Sets the name of this object. - * - * @param string $name The name to set this object's name to. - */ - function getDn() - { - return $this->name . ',' . $GLOBALS['conf']['kolab']['ldap']['basedn']; - } - - /** - * Take in a list of attributes from the backend and map it to our - * internal data array. - * - * @param array $attributes The list of attributes from the backend. - */ - function _fromAttributes($attributes = array()) - { - $this->data['users'] = array(); - foreach ($attributes as $key => $value) { - if (Horde_String::lower($key) == 'member') { - if (is_array($value)) { - foreach ($value as $user) { - $pattern = '/^cn=([^,]+).*$/'; - $results = array(); - preg_match($pattern, $user, $results); - if (isset($results[1])) { - $user = $results[1]; - } - $this->data['users'][$user] = '1'; - } - } else { - $pattern = '/^cn=([^,]+).*$/'; - $results = array(); - preg_match($pattern, $value, $results); - if (isset($results[1])) { - $value = $results[1]; - } - $this->data['users'][$value] = '1'; - } - } elseif ($key == 'mail') { - $this->data['email'] = $value; - } else { - $this->data[$key] = $value; - } - } - } - - /** - * Map this object's attributes from the data array into a format that - * can be stored in an LDAP entry. - * - * @return array The entry array. - */ - function _toAttributes() - { - $attributes = array(); - foreach ($this->data as $key => $value) { - if ($key == 'users') { - foreach ($value as $user => $membership) { - $user = 'cn=' . $user . ',' . $GLOBALS['conf']['kolab']['ldap']['basedn']; - $attributes['member'][] = $user; - } - } elseif ($key == 'email') { - if (!empty($value)) { - $attributes['mail'] = $value; - } - } elseif ($key != 'dn' && $key != 'member') { - $attributes[$key] = !empty($value) ? $value : ' '; - } - } - - return $attributes; - } - -} diff --git a/framework/Group/Group/ldap.php b/framework/Group/Group/ldap.php deleted file mode 100644 index 664539fb1..000000000 --- a/framework/Group/Group/ldap.php +++ /dev/null @@ -1,858 +0,0 @@ - - * @package Horde_Group - */ -class Group_ldap extends Group { - - /** - * LDAP connection handle - */ - var $_ds; - - /** - * Local copy of the global $conf['group']['params'] array. Simply - * for coding convenience. - */ - var $_params; - - /** - * Generated LDAP filter based on the config parameters - */ - var $_filter; - - /** - * Constructor. - */ - function Group_ldap($params) - { - $this->_params = $GLOBALS['conf']['group']['params']; - - $this->_params['gid'] = Horde_String::lower($this->_params['gid']); - $this->_params['memberuid'] = Horde_String::lower($this->_params['memberuid']); - foreach ($this->_params['newgroup_objectclass'] as $key => $val) { - $this->_params['newgroup_objectclass'][$key] = Horde_String::lower($val); - } - - /* Generate LDAP search filter. */ - if (!empty($this->_params['filter'])) { - $this->_filter = $this->_params['filter']; - } elseif (!is_array($this->_params['objectclass'])) { - $this->_filter = 'objectclass=' . $this->_params['objectclass']; - } else { - $this->_filter = ''; - foreach ($this->_params['objectclass'] as $objectclass) { - $this->_filter = '(&' . $this->_filter; - $this->_filter .= '(objectclass=' . $objectclass . '))'; - } - } - - $this->_filter = Horde_String::lower($this->_filter); - } - - /** - * Connects to the LDAP server. - * - * @return boolean True or False based on success of connect and bind. - */ - function _connect() - { - /* Connect to the LDAP server. */ - $this->_ds = @ldap_connect($this->_params['hostspec']); - if (!$this->_ds) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - if (!ldap_set_option($this->_ds, LDAP_OPT_PROTOCOL_VERSION, - $this->_params['version'])) { - Horde::logMessage( - sprintf('Set LDAP protocol version to %d failed: [%d] %s', - $this->_params['version'], - ldap_errno($conn), - ldap_error($conn), - __FILE__, __LINE__)); - } - - /* Start TLS if we're using it. */ - if (!empty($this->_params['tls'])) { - if (!@ldap_start_tls($this->_ds)) { - Horde::logMessage( - sprintf('STARTTLS failed: [%d] %s', - @ldap_errno($this->_ds), - @ldap_error($this->_ds)), - 'ERR'); - } - } - - if (isset($this->_params['binddn'])) { - $bind = @ldap_bind($this->_ds, $this->_params['binddn'], - $this->_params['password']); - } else { - $bind = @ldap_bind($this->_ds); - } - - if (!$bind) { - return PEAR::raiseError(_("Could not bind to LDAP server")); - } - - return true; - } - - /** - * Recursively deletes $dn. $this->_ds MUST already be connected. - * - * @return mixed True if delete was successful, PEAR_Error otherwise. - */ - function _recursive_delete($dn) - { - $search = @ldap_list($this->_ds, $dn, 'objectclass=*', array('')); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $children = @ldap_get_entries($this->_ds, $search); - for ($i = 0; $i < $children['count']; $i++) { - $result = $this->_recursive_delete($children[$i]['dn']); - if (!$result) { - return PEAR::raiseError(sprintf(_("Group_ldap: Unable to delete group \"%s\". This is what the server said: %s"), $this->getName($children[$i]['dn']), @ldap_error($this->_ds))); - } - } - - $result = @ldap_delete($this->_ds, $dn); - if (!$result) { - return PEAR::raiseError(sprintf(_("Group_ldap: Unable to delete group \"%s\". This is what the server said: %s"), $dn, @ldap_error($this->_ds))); - } - - return $result; - } - - /** - * Searches existing groups for the highest gidnumber, and returns - * one higher. - */ - function _nextGid() - { - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $search = @ldap_search($this->_ds, $this->_params['basedn'], $this->_filter); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - - if (!is_array($result) || (count($result) <= 1)) { - return 1; - } - - $nextgid = 0; - for ($i = 0; $i < $result['count']; $i++) { - if ($result[$i]['gidnumber'][0] > $nextgid) { - $nextgid = $result[$i]['gidnumber'][0]; - } - } - - return $nextgid + 1; - } - - /** - * Return a new group object. - * - * @param string $name The group's name. - * @param string $parent The group's parent's ID (DN) - * - * @return LDAP_Group A new group object. - * @throws Horde_Exception - */ - function &newGroup($name, $parent = null) - { - if (empty($name)) { - return PEAR::raiseError(_("Group names must be non-empty")); - } - - try { - $entry = Horde::callHook('groupldap', array($name, $parent)); - } catch (Horde_Exception_HookNotSet $e) { - // Try this simple default and hope it works. - $entry[$this->_params['gid']] = $name; - $entry['objectclass'] = $this->_params['newgroup_objectclass']; - $entry['gidnumber'] = $this->_nextGid(); - } - - $group = new LDAP_Group($name, $parent); - $group->_fromAttributes($entry); - $group->setGroupOb($this); - return $group; - } - - /** - * Return an LDAP_Group object corresponding to the named group, with the - * users and other data retrieved appropriately. - * - * @param string $name The name of the group to retrieve. - * - * @return LDAP_Group The requested group. - */ - function &getGroup($name) - { - $dn = $this->getGroupId($name); - if (is_a($dn, 'PEAR_Error')) { - return PEAR::raiseError($dn->getMessage()); - } - $group = &$this->getGroupById($dn); - return $group; - } - - /** - * Return an LDAP_Object object corresponding to the given dn, with the - * users and other data retrieved appropriately. - * - * @param string $dn The dn of the group to retrieve. - * - * @return LDAP_Object The requested group. - */ - function &getGroupById($dn) - { - static $cache = array(); - - if (!isset($cache[$dn])) { - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $search = @ldap_search($this->_ds, $dn, $this->_filter); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - return PEAR::raiseError(_("Empty result")); - } - - $attributes = array(); - for ($i = 0; $i < $result[0]['count']; $i++) { - if ($result[0][$result[0][$i]]['count'] > 1) { - $attributes[$result[0][$i]] = array(); - for ($j = 0; $j < $result[0][$result[0][$i]]['count']; $j++) { - $attributes[$result[0][$i]][] = $result[0][$result[0][$i]][$j]; - } - } else { - $attributes[$result[0][$i]] = $result[0][$result[0][$i]][0]; - } - } - $attributes['dn'] = $result[0]['dn']; - - $group = new LDAP_Group($this->getGroupName($dn)); - $group->_fromAttributes($attributes); - $group->setGroupOb($this); - $cache[$dn] = $group; - } - - return $cache[$dn]; - } - - /** - * Get a globally unique ID for a group. This really just returns the dn - * for the group, but is included for compatibility with the Group class. - * - * @param LDAP_Object $group The group. - * - * @return string a GUID referring to $group. - */ - function getGUID($group) - { - return $group->get('dn'); - } - - /** - * Add a group to the groups system. The group must first be created with - * Group_ldap::newGroup(), and have any initial users added to it, before - * this function is called. - * - * @param LDAP_Group $group The new group object. - * - * @return mixed True if successful, PEAR_Error otherwise. - */ - function addGroup($group) - { - if (!is_a($group, 'DataTreeObject_Group')) { - return PEAR::raiseError('Groups must be DataTreeObject_Group objects or extend that class.'); - } - - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $dn = $group->get('dn'); - - $entry = $group->_toAttributes(); - $success = @ldap_add($this->_ds, $dn, $entry); - - if (!$success) { - return PEAR::raiseError(sprintf(_("Group_ldap: Unable to add group \"%s\". This is what the server said: "), $group->getName()) . @ldap_error($this->_ds)); - } - - @ldap_close($this->_ds); - - return true; - } - - /** - * Store updated data - users, etc. - of a group to the backend system. - * - * @param LDAP_Object $group The group to update - * - * @return mixed True on success, PEAR_Error otherwise. - * - * @throws Horde_History_Exception - * @throws InvalidArgumentException - */ - function updateGroup($group) - { - if (!is_a($group, 'DataTreeObject_Group')) { - return PEAR::raiseError('Groups must be DataTreeObject_Group objects or extend that class.'); - } - - $entry = $group->_toAttributes(); - - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - // Do not attempt to change an LDAP object's objectClasses - unset($entry['objectclass']); - - $result = @ldap_modify($this->_ds, $group->getId(), $entry); - if (!$result) { - return PEAR::raiseError(sprintf(_("Group_ldap: Unable to update group \"%s\". This is what the server said: %s"), $group->getName(), @ldap_error($this->_ds))); - } - - @ldap_close($this->_ds); - - /* Log the update of the group users on the history log. */ - $history = $GLOBALS['injector']->getInstance('Horde_History'); - $guid = $this->getGUID($group); - foreach ($group->getAuditLog() as $userId => $action) { - $history->log($guid, array('action' => $action, 'user' => $userId), true); - } - $group->clearAuditLog(); - - /* Log the group modification. */ - $history->log($guid, array('action' => 'modify'), true); - return $result; - } - - /** - * Remove a group from the groups system permanently. - * - * @param LDAP_Group $group The group to remove. - * @param boolean $force Recursively delete children groups if true. - * - * @return mixed True on success, PEAR_Error otherwise. - */ - function removeGroup($group, $force = false) - { - if (!is_a($group, 'DataTreeObject_Group')) { - return PEAR::raiseError('Groups must be DataTreeObject_Group objects or extend that class.'); - } - - $dn = $group->getId(); - - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - if ($force) { - return $this->_recursive_delete($dn); - } else { - $result = @ldap_delete($this->_ds, $dn); - if (!$result) { - return PEAR::raiseError(sprintf(_("Group_ldap: Unable to delete group \"%s\". This is what the server said: %s"), $dn, @ldap_error($this->_ds))); - } - } - } - - /** - * Retrieve the name of a group. - * - * @param string $dn The dn of the group to retrieve the name for. - * - * @return string The group's name. - */ - function getGroupName($dn) - { - $dn = Horde_String::convertCharset($dn, Horde_Nls::getCharset(), 'UTF-8'); - $result = @ldap_explode_dn($dn, 1); - if ($result === false) { - return PEAR::raiseError(_("Invalid group ID passed (bad DN syntax)")); - } - - return $result[0]; - } - - /** - * DataTreeObject full names include references to parents, but LDAP does - * not have this concept. This function simply returns the $group - * parameter and is included for compatibility with the Group class. - * - * @param string $group Group name. - * - * @return string $group. - */ - function getGroupShortName($group) - { - return $group; - } - - /** - * Retrieve the ID of the given group. - * - * NOTE: If given a group name, this function can be unreliable if more - * than one group exists with the same name. - * - * @param mixed $group LDAP_Group object, or a group name (string) - * - * @return string The group's ID. - */ - function getGroupId($group) - { - static $cache = array(); - - if (is_a($group, 'LDAP_Group')) { - return $group->get('dn'); - } - - if (!isset($cache[$group])) { - $this->_connect(); - $search = @ldap_search($this->_ds, $this->_params['basedn'], - $this->_params['gid'] . '=' . $group, - array($this->_params['gid'])); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - return PEAR::raiseError(_("Empty result")); - } - $cache[$group] = $result[0]['dn']; - } - - return $cache[$group]; - } - - /** - * Check if a group exists in the system. - * - * @param string $group The group name to check for. - * - * @return boolean True if the group exists, False otherwise. - */ - function exists($group) - { - static $cache = array(); - - if (!isset($cache[$group])) { - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $groupDN = $this->getGroupId($group); - $group = $this->getGroupShortName($group); - - $res = @ldap_compare($this->_ds, $groupDN, $this->_params['gid'], $group); - if ($res === false) { - return PEAR::raiseError(sprintf(_("Internal Error: An attribute must ALWAYS match itself: %s"), @ldap_error($this->_ds))); - } - // $res is True if the group exists, -1 if not, false never - $cache[$group] = ($res === true); - } - - return $cache[$group]; - } - - /** - * Get a list of the parents of a child group. - * - * @param string $dn The fully qualified group dn - * - * @return array Nested array of parents - */ - function getGroupParents($dn) - { - $parent = $this->getGroupParent($dn); - $parents = array(DATATREE_ROOT => 1); - while ($parent != DATATREE_ROOT) { - $parents = array($parent => $parents); - $parent = $this->getGroupParent($parent); - } - return $parents; - } - - /** - * Get the parent of the given group. - * - * @param string $dn The dn of the child group. - * - * @return string The dn of the parent group. - */ - function getGroupParent($dn) - { - $result = @ldap_explode_dn($dn, 0); - if ($result === false) { - return PEAR::raiseError(_("Invalid group ID passed (bad DN syntax)")); - } - - unset($result['count']); - unset($result[0]); - $parent_dn = implode(',', $result); - - if (Horde_String::lower($parent_dn) == Horde_String::lower($GLOBALS['conf']['group']['params']['basedn'])) { - return DATATREE_ROOT; - } else { - return $parent_dn; - } - } - - /** - * Get a list of parents all the way up to the root object for the given - * group. - * - * @param string $dn The dn of the group. - * - * @return array A flat list of all of the parents of the given group, - * hashed in $dn => $name format. - */ - function getGroupParentList($dn) - { - $result = @ldap_explode_dn($dn, 0); - if ($result === false) { - return PEAR::raiseError(_("Invalid group ID passed (bad DN syntax)")); - } - - $num = $result['count']; - unset($result['count']); - unset($result[0]); - - $count = 0; - $parents = array(); - $parent_dn = implode(',', $result); - while ($parent_dn != $this->_params['basedn'] && $count++ != $num) { - $parents[$parent_dn] = $this->getGroupName($parent_dn); - unset($result[$count]); - $parent_dn = implode(',', $result); - } - $parents[DATATREE_ROOT] = DATATREE_ROOT; - - return $parents; - } - - /** - * Get a list of every group, in the format dn => groupname. - * - * @param boolean $refresh If true, the cached value is ignored and the - * group list is refreshed from the group backend. - * - * @return array dn => groupname hash. - */ - function listGroups($refresh = false) - { - static $groups; - - if ($refresh || is_null($groups)) { - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $search = @ldap_search($this->_ds, $this->_params['basedn'], $this->_filter, array($this->_params['gid'])); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - @ldap_sort($this->_ds, $search, $this->_params['gid']); - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - return array(); - } - - $groups = array(); - for ($i = 0; $i < $result['count']; $i++) { - $groups[$result[$i]['dn']] = $this->getGroupName($result[$i]['dn']); - } - } - - return $groups; - } - - /** - * Get a list of every user that is part of the specified group and any - * of its subgroups. - * - * @param string $dn The dn of the parent group. - * - * @return array The complete user list. - */ - function listAllUsers($dn) - { - static $cache = array(); - - if (!isset($cache[$dn])) { - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - $search = @ldap_search($this->_ds, $dn, $this->_filter); - if (!$search) { - return PEAR::raiseError(sprintf(_("Could not reach the LDAP server: %s"), @ldap_error($this->_ds))); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - // Not an error, we just don't have any users in this group. - return array(); - } - - $users = array(); - for ($i = 0; $i < $result['count']; $i++) { - $users = array_merge($users, $this->listUsers($result[$i]['dn'])); - } - - $cache[$dn] = array_keys(array_flip($users)); - } - - return $cache[$dn]; - } - - /** - * Get a list of every group that the given user is a member of. - * - * @param string $user The user to get groups for. - * @param boolean $parentGroups Also return the parents of any groups? - * - * @return array An array of all groups the user is in. - */ - function getGroupMemberships($user, $parentGroups = false) - { - static $cache = array(); - - if (empty($cache[$user])) { - /* Connect to the LDAP server. */ - $success = $this->_connect(); - if (is_a($success, 'PEAR_Error')) { - return PEAR::raiseError($success->getMessage()); - } - - // Set up search filter - $filter = '(' . $this->_params['memberuid'] . '='; - if ($GLOBALS['conf']['group']['params']['attrisdn']) { - $filter .= $GLOBALS['conf']['auth']['params']['uid'] . '='; - } - $filter .= $user; - if ($GLOBALS['conf']['group']['params']['attrisdn']) { - $filter .= ',' . $GLOBALS['conf']['auth']['params']['basedn']; - } - $filter .= ')'; - - // Perform search - $search = @ldap_search($this->_ds, $this->_params['basedn'], $filter); - if (!$search) { - return PEAR::raiseError(_("Could not reach the LDAP server")); - } - - $result = @ldap_get_entries($this->_ds, $search); - @ldap_close($this->_ds); - if (!is_array($result) || (count($result) <= 1)) { - return array(); - } - - $groups = array(); - $current_charset = Horde_Nls::getCharset(); - for ($i = 0; $i < $result['count']; $i++) { - $utf8_dn = Horde_String::convertCharset($result[$i]['dn'], 'UTF-8', $current_charset); - $groups[$utf8_dn] = $this->getGroupName($utf8_dn); - } - - $cache[$user] = $groups; - } - - return $cache[$user]; - } - - /** - * Returns the tree depth of the given group, relative to the base dn. - * 0 is returned for any object directly below the base dn. - * - * @param string $dn The dn of the object. - * - * @return intenger The tree depth of the group. - */ - function getLevel($dn) - { - $base = @ldap_explode_dn($this->_params['basedn'], 0); - if ($base === false) { - return PEAR::raiseError(_("Invalid basedn configured")); - } - - $group = @ldap_explode_dn($dn, 0); - if ($group === false) { - return PEAR::raiseError(_("Invalid group ID passed (bad DN syntax)")); - } - - return $group['count'] - $base['count'] - 1; - } - -} - -/** - * Extension of the DataTreeObject_Group class for storing group information - * in an LDAP directory. - * - * @author Ben Chavet - * @package Horde_Group - */ -class LDAP_Group extends DataTreeObject_Group { - - /** - * Constructor. - * - * @param string $name The name of this group. - * @param string $parent The dn of the parent of this group. - */ - function LDAP_Group($name, $parent = null) - { - parent::DataTreeObject_Group($name); - if ($parent) { - $this->data['dn'] = Horde_String::lower($GLOBALS['conf']['group']['params']['gid']) . '=' . $name . ',' . $parent; - } else { - $this->data['dn'] = Horde_String::lower($GLOBALS['conf']['group']['params']['gid']) . '=' . $name . - ',' . Horde_String::lower($GLOBALS['conf']['group']['params']['basedn']); - } - } - - /** - * Get a list of every user that is part of this group (and only - * this group). - * - * @return array The user list. - */ - function listUsers() - { - return $this->_groupOb->listUsers($this->data['dn']); - } - - /** - * Get a list of every user that is a member of this group and any of - * it's subgroups. - * - * @return array The complete user list. - */ - function listAllUsers() - { - return $this->_groupOb->listAllUsers($this->data['dn']); - } - - /** - * Take in a list of attributes from the backend and map it to our - * internal data array. - * - * @param array $attributes The list of attributes from the backend. - */ - function _fromAttributes($attributes = array()) - { - $this->data['users'] = array(); - foreach ($attributes as $key => $value) { - if (Horde_String::lower($key) == Horde_String::lower($GLOBALS['conf']['group']['params']['memberuid'])) { - if (is_array($value)) { - foreach ($value as $user) { - if ($GLOBALS['conf']['group']['params']['attrisdn']) { - $pattern = '/^' . $GLOBALS['conf']['auth']['params']['uid'] . '=([^,]+).*$/'; - $results = array(); - preg_match($pattern, $user, $results); - if (isset($results[1])) { - $user = $results[1]; - } - } - $this->data['users'][$user] = '1'; - } - } else { - if ($GLOBALS['conf']['group']['params']['attrisdn']) { - $pattern = '/^' . $GLOBALS['conf']['auth']['params']['uid'] . '=([^,]+).*$/'; - $results = array(); - preg_match($pattern, $value, $results); - if (isset($results[1])) { - $value = $results[1]; - } - } - $this->data['users'][$value] = '1'; - } - } elseif ($key == 'mail') { - $this->data['email'] = $value; - } else { - $this->data[$key] = $value; - } - } - } - - /** - * Map this object's attributes from the data array into a format that - * can be stored in an LDAP entry. - * - * @return array The entry array. - */ - function _toAttributes() - { - $attributes = array(); - foreach ($this->data as $key => $value) { - if ($key == 'users') { - foreach ($value as $user => $membership) { - if ($GLOBALS['conf']['group']['params']['attrisdn']) { - $user = $GLOBALS['conf']['auth']['params']['uid'] . - '=' . $user . ',' . $GLOBALS['conf']['auth']['params']['basedn']; - } - $attributes[Horde_String::lower($GLOBALS['conf']['group']['params']['memberuid'])][] = $user; - } - } elseif ($key == 'email') { - if (!empty($value)) { - $attributes['mail'] = $value; - } - } elseif ($key != 'dn' && $key != Horde_String::lower($GLOBALS['conf']['group']['params']['memberuid'])) { - $attributes[$key] = !empty($value) ? $value : ' '; - } - } - - return $attributes; - } - -} diff --git a/framework/Group/Group/mock.php b/framework/Group/Group/mock.php deleted file mode 100644 index 5c57a1f01..000000000 --- a/framework/Group/Group/mock.php +++ /dev/null @@ -1,280 +0,0 @@ - - * @package Horde_Group - */ -class Group_mock extends Group { - - /** - * Constructor. - */ - function Group_mock() - { - } - - /** - * Initializes the object. - */ - function __wakeup() - { - } - - /** - * Returns a new group object. - * - * @param string $name The group's name. - * @param string $parent The group's parent's name. - * - * @return DataTreeObject_Group A new group object. - */ - function &newGroup($name, $parent = GROUP_ROOT) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Returns a DataTreeObject_Group object corresponding to the named group, - * with the users and other data retrieved appropriately. - * - * @param string $name The name of the group to retrieve. - */ - function &getGroup($name) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Returns a DataTreeObject_Group object corresponding to the given unique - * ID, with the users and other data retrieved appropriately. - * - * @param integer $cid The unique ID of the group to retrieve. - */ - function &getGroupById($cid) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Adds a group to the groups system. The group must first be created with - * Group::newGroup(), and have any initial users added to it, before this - * function is called. - * - * @param DataTreeObject_Group $group The new group object. - */ - function addGroup($group) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Stores updated data - users, etc. - of a group to the backend system. - * - * @param DataTreeObject_Group $group The group to update. - */ - function updateGroup($group) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Removes a group from the groups system permanently. - * - * @param DataTreeObject_Group $group The group to remove. - * @param boolean $force Force to remove every child. - */ - function removeGroup($group, $force = false) - { - return PEAR::raiseError(_("Unsupported")); - } - - /** - * Retrieves the name of a group. - * - * @param integer|DataTreeObject_Group $gid The id of the group or the - * group object to retrieve the - * name for. - * - * @return string The group's name. - */ - function getGroupName($gid) - { - return ''; - } - - /** - * Strips all parent references off of the given group name. - * - * @param string $group Name of the group. - * - * @return The name of the group without parents. - */ - function getGroupShortName($group) - { - return ''; - } - - /** - * Retrieves the ID of a group. - * - * @param string|DataTreeObject_Group $group The group name or object to - * retrieve the ID for. - * - * @return integer The group's ID. - */ - function getGroupId($group) - { - return ''; - } - - /** - * Check if a group exists in the system. - * - * @param string $group The group to check. - * - * @return boolean True if the group exists, false otherwise. - */ - function exists($group) - { - return false; - } - - /** - * Returns a tree of the parents of a child group. - * - * @param integer $gid The id of the child group. - * - * @return array The group parents tree, with groupnames as the keys. - */ - function getGroupParents($gid) - { - return array(); - } - - /** - * Returns the single parent ID of the given group. - * - * @param integer $gid The DataTree ID of the child group. - * - * @return integer The parent of the given group. - */ - function getGroupParent($gid) - { - return null; - } - - /** - * Returns a flat list of the parents of a child group - * - * @param integer $gid The id of the group. - * - * @return array A flat list of all of the parents of $group, hashed in - * $id => $name format. - */ - function getGroupParentList($gid) - { - return array(); - } - - /** - * Returns a list of all groups, in the format id => groupname. - * - * @param boolean $refresh If true, the cached value is ignored and the - * group list is refreshed from the group backend. - * - * @return array ID => groupname hash. - */ - function listGroups($refresh = false) - { - return array(); - } - - /** - * Get a list of every user that is a part of this group ONLY. - * - * @param integer $gid The ID of the group. - * - * @return array The user list. - */ - function listUsers($gid) - { - return array(); - } - - /** - * Get a list of every user that is part of the specified group - * and any of its subgroups. - * - * @param integer $group The ID of the parent group. - * - * @return array The complete user list. - */ - function listAllUsers($gid) - { - return array(); - } - - /** - * Get a list of every group that $user is in. - * - * @param string $user The user to get groups for. - * @param boolean $parentGroups Also return the parents of any groups? - * - * @return array An array of all groups the user is in. - */ - function getGroupMemberships($user, $parentGroups = false) - { - return array(); - } - - /** - * Say if a user is a member of a group or not. - * - * @param string $user The name of the user. - * @param integer $gid The ID of the group. - * @param boolean $subgroups Return true if the user is in any subgroups - * of group with ID $gid, also. - * - * @return boolean - */ - function userIsInGroup($user, $gid, $subgroups = true) - { - return false; - } - - /** - * Returns the nesting level of the given group. 0 is returned for any - * object directly below GROUP_ROOT. - * - * @param integer $gid The ID of the group. - * - * @return The nesting level of the group. - */ - function getLevel($gid) - { - return 0; - } - - /** - * Stores the object in the session cache. - */ - function shutdown() - { - } - - /** - * Returns the properties that need to be serialized. - * - * @return array List of serializable properties. - */ - function __sleep() - { - } - -} diff --git a/framework/Group/Group/sql.php b/framework/Group/Group/sql.php deleted file mode 100644 index 442da7b98..000000000 --- a/framework/Group/Group/sql.php +++ /dev/null @@ -1,891 +0,0 @@ - - * @package Horde_Group - */ -class Group_sql extends Group { - - /** - * Boolean indicating whether or not we're connected to the SQL server. - * - * @var boolean - */ - var $_connected = false; - - /** - * Handle for the current database connection. - * - * @var DB - */ - var $_db; - - /** - * Handle for the current database connection, used for writing. Defaults - * to the same handle as $db if a separate write database is not required. - * - * @var DB - */ - var $_write_db; - - /** - * Constructor. - */ - function Group_sql($params) - { - $this->_params = $params; - } - - /** - * Initializes the object. - */ - function __wakeup() - { - } - - /** - * Returns the properties that need to be serialized. - * - * @return array List of serializable properties. - */ - function __sleep() - { - } - - /** - * Stores the object in the session cache. - */ - function shutdown() - { - } - - /** - * Replace all occurences of ':' in an object name with '.'. - * - * @param string $name The name of the object. - * - * @return string The encoded name. - */ - function encodeName($name) - { - return str_replace(':', '.', $name); - } - - /** - * Returns a new group object. - * - * @param string $name The group's name. - * @param string $parent The group's parent's name. - * - * @return SQLObject_Group A new group object. - */ - function &newGroup($name, $parent = GROUP_ROOT) - { - if (empty($name)) { - return PEAR::raiseError(_("Group names must be non-empty")); - } - - if ($parent != GROUP_ROOT) { - $name = $this->getGroupName($parent) . ':' . $this->encodeName($name); - } - - $group = new SQLObject_Group($name); - $group->setGroupOb($this); - return $group; - } - - /** - * Returns a SQLObject_Group object corresponding to the named group, - * with the users and other data retrieved appropriately. - * - * @param string $name The name of the group to retrieve. - */ - function &getGroup($name) - { - if (!isset($this->_groupCache[$name])) { - $this->_connect(); - $sql = 'SELECT group_uid, group_email FROM horde_groups WHERE group_name = ?'; - $group = $this->_db->getRow($sql, array($name), DB_FETCHMODE_ASSOC); - - if (is_a($group, 'PEAR_Error')) { - return $group; - } elseif (empty($group)) { - return PEAR::raiseError($name . ' does not exist'); - } - - $sql = 'SELECT user_uid FROM horde_groups_members ' - . ' WHERE group_uid = ? ORDER BY user_uid ASC'; - $users = $this->_db->getCol($sql, 0, array($group['group_uid'])); - if (is_a($users, 'PEAR_Error')) { - return $users; - } - - $object = new SQLObject_Group($name); - $object->id = $group['group_uid']; - $object->data['email'] = $group['group_email']; - - if (!empty($users)) { - $object->data['users'] = array_flip($users); - } - - $this->_groupCache[$name] = $object; - $this->_groupCache[$name]->setGroupOb($this); - $this->_groupMap[$this->_groupCache[$name]->getId()] = $name; - } - - return $this->_groupCache[$name]; - } - - /** - * Returns a SQLObject_Group object corresponding to the given unique - * ID, with the users and other data retrieved appropriately. - * - * @param integer $cid The unique ID of the group to retrieve. - */ - function &getGroupById($cid) - { - if (isset($this->_groupMap[$cid])) { - return $this->_groupCache[$this->_groupMap[$cid]]; - } - - $this->_connect(); - $sql = 'SELECT group_name, group_email FROM horde_groups WHERE group_uid = ?'; - $row = $this->_db->getRow($sql, array($cid), DB_FETCHMODE_ASSOC); - - if (is_a($row, 'PEAR_Error')) { - return $row; - } elseif (empty($row)) { - return PEAR::raiseError($cid . ' does not exist'); - } - - $sql = 'SELECT user_uid FROM horde_groups_members ' - . ' WHERE group_uid = ? ORDER BY user_uid ASC'; - $users = $this->_db->getCol($sql, 0, array($cid)); - if (is_a($users, 'PEAR_Error')) { - return $users; - } - - $group = new SQLObject_Group($row['group_name']); - $group->id = $cid; - $group->data['email'] = $row['group_email']; - - if (!empty($users)) { - $group->data['users'] = array_flip($users); - } - - $group->setGroupOb($this); - $name = $group->getName(); - $this->_groupCache[$name] = &$group; - $this->_groupMap[$cid] = $name; - - return $group; - } - - /** - * Adds a group to the groups system. The group must first be created with - * Group::newGroup(), and have any initial users added to it, before this - * function is called. - * - * @param SQLObject_Group $group The new group object. - * - * @throws Horde_History_Exception - * @throws InvalidArgumentException - */ - function addGroup(&$group) - { - if (!is_a($group, 'SQLObject_Group')) { - return PEAR::raiseError('Groups must be SQLObject_Group objects or extend that class.'); - } - - $this->_connect(); - $group->setGroupOb($this); - $name = $group->getName(); - - $email = isset($group->data['email']) ? $group->data['email'] : ''; - $group_id = $this->_write_db->nextId('horde_groups'); - if (is_a($group_id, 'PEAR_Error')) { - return $group_id; - } - - $group->id = $group_id; - $query = 'INSERT INTO horde_groups (group_uid, group_name, group_parents, group_email) VALUES (?, ?, ?, ?)'; - $result = $this->_write_db->query($query, array($group->id, $name, '', $email)); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - if (!empty($group->data['users'])) { - $query = 'INSERT INTO horde_groups_members (group_uid, user_uid)' - .' VALUES (' . (int)$group->id . ', ?)'; - $sth = $this->_write_db->prepare($query); - $result = $this->_write_db->executeMultiple($sth, $group->data['users']); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - } - - $this->_groupCache[$name] = &$group; - $this->_groupMap[$group_id] = $name; - if (isset($this->_groupList)) { - $this->_groupList[$group_id] = $name; - } - - /* Log the addition of the group in the history log. */ - $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'add'), true); - - return $result; - } - - /** - * Stores updated data - users, etc. - of a group to the backend system. - * - * @param SQLObject_Group $group The group to update. - * - * @throws Horde_History_Exception - * @throws InvalidArgumentException - */ - function updateGroup($group) - { - if (!is_a($group, 'SQLObject_Group')) { - return PEAR::raiseError('Groups must be SQLObject_Group objects or extend that class.'); - } - - $this->_connect(); - - $query = 'UPDATE horde_groups SET group_email = ? WHERE group_uid = ?'; - $result = $this->_write_db->query($query, array($this->data['email'], $this->id)); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $query = 'DELETE FROM horde_groups_members WHERE group_uid = ?'; - $result = $this->_write_db->query($query, array($this->id)); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $query = 'INSERT INTO horde_groups_members (group_uid, user_uid)' - .' VALUES (' . (int)$this->id . ', ?)'; - $sth = $this->_write_db->prepare($query); - $result = $this->_groupOb->_write_db->executeMultiple($sth, $this->data['users']); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $this->_groupCache[$group->getName()] = &$group; - - /* Log the update of the group users on the history log. */ - $history = $GLOBALS['injector']->getInstance('Horde_History'); - $guid = $this->getGUID($group); - foreach ($group->getAuditLog() as $userId => $action) { - $history->log($guid, array('action' => $action, 'user' => $userId), true); - } - - $group->clearAuditLog(); - - /* Log the group modification. */ - $history->log($guid, array('action' => 'modify'), true); - return $result; - } - - /** - * Removes a group from the groups system permanently. - * - * @param SQLObject_Group $group The group to remove. - * @param boolean $force Force to remove every child. - * - * @throws Horde_History_Exception - * @throws InvalidArgumentException - */ - function removeGroup($group, $force = false) - { - if (!is_a($group, 'SQLObject_Group')) { - return PEAR::raiseError('Groups must be SQLObject_Group objects or extend that class.'); - } - - $this->_connect(); - $id = $group->getId(); - $name = $group->getName(); - unset($this->_groupMap[$id]); - if (isset($this->_groupList)) { - unset($this->_groupList[$id]); - } - unset($this->_groupCache[$name]); - - $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'delete'), true); - - $query = 'DELETE FROM horde_groups_members WHERE group_uid = ?'; - $result = $this->_write_db->query($query, array($id)); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $query = 'DELETE FROM horde_groups WHERE group_uid = ?'; - $result = $this->_write_db->query($query, array($id)); - if (!$force || is_a($result, 'PEAR_Error')) { - return $result; - } - - $query = 'DELETE FROM horde_groups WHERE group_name LIKE ?'; - return $this->_write_db->query($query, array($name . ':%')); - } - - /** - * Retrieves the name of a group. - * - * @param integer|SQLObject_Group $gid The id of the group or the - * group object to retrieve the - * name for. - * - * @return string The group's name. - */ - function getGroupName($gid) - { - if (is_a($gid, 'SQLObject_Group')) { - $gid = $gid->getId(); - } - - if (isset($this->_groupMap[$gid])) { - return $this->_groupMap[$gid]; - } - if (isset($this->_groupList[$gid])) { - return $this->_groupList[$gid]; - } - - $this->_connect(); - $query = 'SELECT group_name FROM horde_groups WHERE group_uid = ?'; - return $this->_db->getOne($query, $gid); - } - - /** - * Strips all parent references off of the given group name. - * - * @param string $group Name of the group. - * - * @return The name of the group without parents. - */ - function getGroupShortName($group) - { - /* If there are several components to the name, explode and get the - * last one, otherwise just return the name. */ - if (strpos($group, ':') !== false) { - $name = explode(':', $group); - return array_pop($name); - } - - return $group; - } - - /** - * Retrieves the ID of a group. - * - * @param string|SQLObject_Group $group The group name or object to - * retrieve the ID for. - * - * @return integer The group's ID. - */ - function getGroupId($group) - { - if (is_a($group, 'SQLObject_Group')) { - return $group->getId(); - } - - $id = array_search($group, $this->_groupMap); - if ($id !== false) { - return $id; - } - if (isset($this->_groupList)) { - $id = array_search($group, $this->_groupList); - if ($id !== false) { - return $id; - } - } - - $this->_connect(); - $query = 'SELECT group_uid FROM horde_groups WHERE group_name = ?'; - return $this->_db->getOne($query, $group); - } - - /** - * Check if a group exists in the system. - * - * @param string $group The group to check. - * - * @return boolean True if the group exists, false otherwise. - */ - function exists($group) - { - if (isset($this->_groupCache[$group]) || - (isset($this->_groupList) && - array_search($group, $this->_groupList) !== false)) { - return true; - } - - $this->_connect(); - $query = 'SELECT COUNT(*) FROM horde_groups WHERE group_name = ?'; - return (bool)$this->_db->getOne($query, $group); - } - - /** - * Returns a tree of the parents of a child group. - * - * @param integer $gid The id of the child group. - * - * @return array The group parents tree, with groupnames as the keys. - */ - function getGroupParents($gid) - { - if (!isset($this->_parentTree[$gid])) { - $name = $this->getGroupName($gid); - $this->_connect(); - $parents = $this->_getGroupParents($name); - if (is_a($parents, 'PEAR_Error')) { - return $parents; - } - - $this->_parentTree[$gid] = $parents; - } - - return $this->_parentTree[$gid]; - } - - /** - * 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. - */ - function _getGroupParents($child) - { - if (($pos = strrpos($child, ':')) !== false) { - $child = substr($child, 0, $pos); - } - - return $this->_getParents($child); - } - - /** - */ - function _getParents($parents) - { - $mother = array(); - if (!empty($parents)) { - $pname = $parents; - $parents = substr($parents, 0, strrpos($parents, ':')); - $mother[$pname] = $this->_getParents($parents); - } else { - return array(GROUP_ROOT => true); - } - - return $mother; - } - - /** - * Returns the single parent ID of the given group. - * - * @param integer $gid The ID of the child group. - * - * @return integer The parent of the given group. - */ - function getGroupParent($gid) - { - if (!isset($this->_groupParents[$gid])) { - $this->_connect(); - - $name = $this->getGroupName($gid); - if (is_a($name, 'PEAR_Error')) { - return $name; - } - - if (($pos = strrpos($name, ':')) !== false) { - $this->_groupParents[$gid] = $this->getGroupId(substr($name, 0, $pos)); - } else { - $this->_groupParents[$gid] = GROUP_ROOT; - } - } - - return $this->_groupParents[$gid]; - } - - /** - * Returns a flat list of the parents of a child group - * - * @param integer $gid The id of the group. - * - * @return array A flat list of all of the parents of $group, hashed in - * $id => $name format. - */ - function getGroupParentList($gid) - { - if (!isset($this->_groupParentList[$gid])) { - $name = $this->getGroupName($gid); - $pos = strpos($name, ':'); - if ($pos == false) { - $this->_groupParentList[$gid] = array(); - return $this->_groupParentList[$gid]; - } - - $parents = array(); - while ($pos) { - $name = substr($name, 0, $pos); - $parents[] = $name; - $pos = strpos($name, ':'); - } - - $query = 'SELECT group_uid, group_name FROM horde_groups ' - . ' WHERE group_name IN (' . str_repeat('?, ', count($parents) - 1) . '?) '; - $parents = $this->_db->getAssoc($query, false, $parents); - if (is_a($parents, 'PEAR_Error')) { - return $parents; - } - - $this->_groupParentList[$gid] = $parents; - } - - return $this->_groupParentList[$gid]; - } - - /** - * Returns a flat list of the parents of a child group - * - * @param integer $gid The id of the group. - * - * @return array A flat list of all of the parents of $group, hashed in - * $id => $name format. - */ - function _getGroupParentNameList($name) - { - $parents = array(); - - while ($pos) { - $name = substr($name, 0, $pos); - $parents[] = $name; - $pos = strpos($name, ':'); - } - - return $parents; - } - - /** - * Returns a list of all groups, in the format id => groupname. - * - * @param boolean $refresh If true, the cached value is ignored and the - * group list is refreshed from the group backend. - * - * @return array ID => groupname hash. - */ - function listGroups($refresh = false) - { - if ($refresh || !isset($this->_groupList)) { - $this->_connect(); - $sql = 'SELECT group_uid, group_name FROM horde_groups ORDER BY group_uid'; - $this->_groupList = $this->_db->getAssoc($sql); - } - - return $this->_groupList; - } - - /** - * Get a list of every user that is part of the specified group - * and any of its subgroups. - * - * @param integer $group The ID of the parent group. - * - * @return array The complete user list. - */ - function listAllUsers($gid) - { - if (!isset($this->_subGroups[$gid])) { - // Get a list of every group that is a sub-group of $group. - $name = $this->getGroupName($gid); - $query = 'SELECT group_uid FROM horde_groups WHERE group_name LIKE ?'; - $parents = $this->_db->getCol($query, 0, array($name . ':%')); - $this->_subGroups[$gid] = $parents; - $this->_subGroups[$gid][] = $gid; - } - - $users = array(); - foreach ($this->_subGroups[$gid] as $groupId) { - $users = array_merge($users, $this->listUsers($groupId)); - } - - return array_values(array_flip(array_flip($users))); - } - - /** - * Get a list of every group that $user is in. - * - * @param string $user The user to get groups for. - * @param boolean $parentGroups Also return the parents of any groups? - * - * @return array An array of all groups the user is in. - */ - function getGroupMemberships($user, $parentGroups = false) - { - if (isset($_SESSION['horde']['groups']['m'][$user][$parentGroups])) { - return $_SESSION['horde']['groups']['m'][$user][$parentGroups]; - } - - $this->_connect(); - - $sql = 'SELECT g.group_uid AS group_uid, g.group_name AS group_name FROM horde_groups g, horde_groups_members m ' - . ' WHERE m.user_uid = ? AND g.group_uid = m.group_uid ORDER BY g.group_name'; - $result = $this->_db->query($sql, $user); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - $groups = array(); - while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC)) { - $groups[(int)$row['group_uid']] = $this->getGroupShortName($row['group_name']); - } - - if ($parentGroups) { - foreach ($groups as $id => $g) { - $parents = $this->getGroupParentList($id); - if (is_a($parents, 'PEAR_Error')) { - return $parents; - } - $groups += $parents; - } - } - - $_SESSION['horde']['groups']['m'][$user][$parentGroups] = $groups; - return $groups; - } - - /** - * Say if a user is a member of a group or not. - * - * @param string $user The name of the user. - * @param integer $gid The ID of the group. - * @param boolean $subgroups Return true if the user is in any subgroups - * of group with ID $gid, also. - * - * @return boolean - */ - function userIsInGroup($user, $gid, $subgroups = true) - { - if (isset($_SESSION['horde']['groups']['i'][$user][$subgroups][$gid])) { - return $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid]; - } - - if ($subgroups) { - $groups = $this->getGroupMemberships($user, true); - if (is_a($groups, 'PEAR_Error')) { - Horde::logMessage($groups, 'ERR'); - return false; - } - - $result = !empty($groups[$gid]); - } else { - $this->_connect(); - $query = 'SELECT COUNT(*) FROM horde_groups_members WHERE group_uid = ? AND user_uid = ?'; - $result = $this->_db->getOne($query, array($gid, $user)); - - } - - $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid] = (bool)$result; - return (bool)$result; - } - - /** - * Attempts to open a persistent connection to the sql server. - * - * @return boolean True on success. - * @throws Horde_Exception - */ - function _connect() - { - if ($this->_connected) { - return true; - } - if (!isset($this->_params['database'])) { - $this->_params['database'] = ''; - } - if (!isset($this->_params['username'])) { - $this->_params['username'] = ''; - } - if (!isset($this->_params['hostspec'])) { - $this->_params['hostspec'] = ''; - } - - /* Connect to the sql server using the supplied parameters. */ - require_once 'DB.php'; - $this->_write_db = DB::connect($this->_params, - array('persistent' => !empty($this->_params['persistent']), - 'ssl' => !empty($this->_params['ssl']))); - if (is_a($this->_write_db, 'PEAR_Error')) { - throw new Horde_Exception_Prior($this->_write_db); - } - - /* Set DB portability options. */ - switch ($this->_write_db->phptype) { - case 'mssql': - $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); - break; - default: - $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); - } - - /* Check if we need to set up the read DB connection seperately. */ - if (!empty($this->_params['splitread'])) { - $params = array_merge($this->_params, $this->_params['read']); - $this->_db = DB::connect($params, - array('persistent' => !empty($params['persistent']), - 'ssl' => !empty($params['ssl']))); - if (is_a($this->_db, 'PEAR_Error')) { - throw new Horde_Exception_Prior($this->_db); - } - - /* Set DB portability options. */ - switch ($this->_db->phptype) { - case 'mssql': - $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); - break; - default: - $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); - } - } else { - /* Default to the same DB handle for the writer too. */ - $this->_db = $this->_write_db; - } - - $this->_connected = true; - return true; - } - -} - -/** - * Extension of the SQLObject class for storing Group information - * in the Categories driver. If you want to store specialized Group - * information, you should extend this class instead of extending - * SQLObject directly. - * - * @author Duck - * @package Horde_Group - */ -class SQLObject_Group extends DataTreeObject_Group { - - /** - * The unique name of this object. - * These names have the same requirements as other object names - they must - * be unique, etc. - * - * @var string - */ - var $name; - - /** - * The unique name of this object. - * These names have the same requirements as other object names - they must - * be unique, etc. - * - * @var integer - */ - var $id; - - /** - * Key-value hash that will be serialized. - * - * @see getData() - * @var array - */ - var $data = array(); - - /** - * The SQLObject_Group constructor. Just makes sure to call - * the parent constructor so that the group's name is set - * properly. - * - * @param string $name The name of the group. - */ - function SQLObject_Group($name) - { - $this->name = $name; - } - - /** - * Gets the ID of this object. - * - * @return string The object's ID. - */ - function getId() - { - return $this->id; - } - - /** - * Gets the name of this object. - * - * @return string The object name. - */ - function getName() - { - return $this->name; - } - - /** - * 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. - */ - function get($attribute) - { - return isset($this->data[$attribute]) - ? $this->data[$attribute] - : null; - } - - /** - * Sets one of the attributes of the object. - * - * @param string $attribute The attribute to set. - * @param mixed $value The value for $attribute. - */ - function set($attribute, $value) - { - $this->data[$attribute] = $value; - } - - /** - * Save group - */ - function save() - { - if (isset($this->data['email'])) { - $query = 'UPDATE horde_groups SET group_email = ? WHERE group_uid = ?'; - $result = $this->_groupOb->_write_db->query($query, array($this->data['email'], $this->id)); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - } - - $query = 'DELETE FROM horde_groups_members WHERE group_uid = ?'; - $result = $this->_groupOb->_write_db->query($query, array($this->id)); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - - if (!empty($this->data['users'])) { - $query = 'INSERT INTO horde_groups_members (group_uid, user_uid)' - .' VALUES (' . $this->_groupOb->_write_db->quote($this->id) . ', ?)'; - $sth = $this->_groupOb->_write_db->prepare($query); - $result = $this->_groupOb->_write_db->executeMultiple($sth, array_keys($this->data['users'])); - if (is_a($result, 'PEAR_Error')) { - return $result; - } - } - } - -} diff --git a/framework/Group/lib/Horde/Group.php b/framework/Group/lib/Horde/Group.php new file mode 100644 index 000000000..7f7d73ff7 --- /dev/null +++ b/framework/Group/lib/Horde/Group.php @@ -0,0 +1,704 @@ + + * @author Chuck Hagenbuch + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group +{ + /** The parent Group node */ + const ROOT = -1; + + /** + * Group driver parameters + * + * @var array + */ + protected $_params; + + /** + * Pointer to a DataTree instance to manage the different groups. + * + * @var DataTree + */ + protected $_datatree; + + /** + * Cache of previously retrieved group objects. + * + * @var array + */ + protected $_groupCache = array(); + + /** + * Id-name-map of already cached group objects. + * + * @var array + */ + protected $_groupMap = array(); + + /** + * Id-name-hash of all existing groups. + * + * @var array + */ + protected $_groupList; + + /** + * List of sub groups. + * + * @see listAllUsers() + * @var array + */ + protected $_subGroups = array(); + + /** + * Cache of parent groups. + * + * This is an array with group IDs as keys and the integer group id of the + * direct parent as values. + * + * @see getGroupParent() + * @var array + */ + protected $_groupParents = array(); + + /** + * Cache of parent group trees. + * + * This is an array with group IDs as keys and id-name-hashes of all + * parents as values. + * + * @see getGroupParentList() + * @var array + */ + protected $_groupParentList = array(); + + /** + * Cache of parents tree. + * + * @see getGroupParents() + * @var array + */ + protected $_parentTree = array(); + + /** + * Hash of groups of certain users. + * + * @see getGroupMemberShips() + * @var array + */ + protected $_userGroups; + + /** + * Attempts to return a concrete Group instance based on $driver. + * + * @param mixed $driver The type of concrete Group subclass to return. + * @param array $params A hash containing any additional configuration or + * connection parameters a subclass might need. + * + * @return Horde_Group The newly created concrete Group instance. + * @throws Horde_Group_Exception + */ + static public function factory($driver = '', $params = null) + { + if (is_null($params)) { + $params = Horde::getDriverConfig('group', $driver); + } + + $class = self::_loadDriver($driver); + if (class_exists($class)) { + return new $class($params); + } + + throw new Horde_Group_Exception('Class definition of ' . $class . ' not found.'); + } + + /** + * Attempts to return a reference to a concrete Group instance. + * It will only create a new instance if no Group instance + * currently exists. + * + * @return Group The concrete Group reference, or false on an error. + */ + public static function singleton() + { + static $group; + + if (isset($group)) { + return $group; + } + + $group_driver = null; + $group_params = null; + $auth = $GLOBALS['injector']->getInstance('Horde_Auth')->getOb(); + if ($auth->hasCapability('groups')) { + $group_driver = $auth->getDriver(); + $group_params = $auth; + } elseif (!empty($GLOBALS['conf']['group']['driver']) && + $GLOBALS['conf']['group']['driver'] != 'datatree') { + $group_driver = $GLOBALS['conf']['group']['driver']; + $group_params = Horde::getDriverConfig('group', $group_driver); + } + + self::_loadDriver($group_driver); + + $group = null; + if (!empty($GLOBALS['conf']['group']['cache'])) { + $session = new Horde_SessionObjects(); + $group = $session->query('horde_group'); + } + + if (!$group) { + $group = self::factory($group_driver, $group_params); + } + + if (!empty($GLOBALS['conf']['group']['cache'])) { + register_shutdown_function(array($group, 'shutdown')); + } + + return $group; + } + + /** + */ + protected static function _loadDriver($driver) + { + if (!$driver) { + $class = __CLASS__; + } else { + $driver = ucfirst(strtolower(basename($driver))); + $class = __CLASS__ . '_' . $driver; + if (!class_exists($class)) { + } + } + + return $class; + } + + /** + * Constructor. + * + * @param array $params Configuration parameters. + */ + public function __construct(array $params = array()) + { + $this->_params = $params; + $this->__wakeup(); + } + + /** + * Stores the object in the session cache. + */ + public function shutdown() + { + $GLOBALS['injector']->getInstance('Horde_SessionObjects')->overwrite('horde_group', $this, false); + } + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + return array_diff(array_keys(get_class_vars(__CLASS__)), array('_datatree')); + } + /** + * Initializes the object. + * + * @throws Horde_Group_Exception + */ + public function __wakeup() + { + global $conf; + + if (empty($conf['datatree']['driver'])) { + throw new Horde_Group_Exception('You must configure a DataTree backend to use Groups.'); + } + + $driver = $conf['datatree']['driver']; + $this->_datatree = DataTree::singleton($driver, array_merge(Horde::getDriverConfig('datatree', $driver), array('group' => 'horde.groups'))); + + foreach (array_keys($this->_groupCache) as $name) { + $this->_groupCache[$name]->setGroupOb($this); + $this->_groupCache[$name]->setDataTree($this->_datatree); + } + } + + /** + * Returns a new group object. + * + * @param string $name The group's name. + * @param string $parent The group's parent's name. + * + * @return Horde_Group_DataTreeObject A new group object. + * @throws Horde_Group_Exception + */ + public function newGroup(string $name, $parent = self::ROOT) + { + if ($parent != self::ROOT) { + $name = $this->getGroupName($parent) . ':' . DataTree::encodeName($name); + } + + $group = new Horde_Group_DataTreeObject($name); + $group->setGroupOb($this); + + return $group; + } + + /** + * Returns a group object corresponding to the named group, with the users + * and other data retrieved appropriately. + * + * @param string $name The name of the group to retrieve. + * + * @return Horde_Group_DataTreeObject Group object. + */ + public function getGroup($name) + { + if (!isset($this->_groupCache[$name])) { + $this->_groupCache[$name] = $this->_datatree->getObject($name, 'Horde_Group_DataTreeObject'); + if (!($this->_groupCache[$name] instanceof PEAR_Error)) { + $this->_groupCache[$name]->setGroupOb($this); + $this->_groupMap[$this->_groupCache[$name]->getId()] = $name; + } + } + + return $this->_groupCache[$name]; + } + + /** + * Returns a group object corresponding to the given unique ID, with the + * users and other data retrieved appropriately. + * + * @param integer $cid The unique ID of the group to retrieve. + * + * @return Horde_Group_DataTreeObject Group object. + */ + public function getGroupById($cid) + { + if (isset($this->_groupMap[$cid])) { + $group = $this->_groupCache[$this->_groupMap[$cid]]; + } else { + $group = $this->_datatree->getObjectById($cid, 'Horde_Group_DataTreeObject'); + if (!($group instanceof PEAR_Error)) { + $group->setGroupOb($this); + $name = $group->getName(); + $this->_groupCache[$name] = &$group; + $this->_groupMap[$cid] = $name; + } + } + + return $group; + } + + /** + * Returns a globally unique ID for a group. + * + * @param DataTreeObject_Group $group The group. + * + * @return string A GUID referring to $group. + */ + public function getGUID($group) + { + return 'horde:group:' . $this->getGroupId($group); + } + + /** + * Adds a group to the groups system. The group must first be created with + * newGroup(), and have any initial users added to it, before this + * function is called. + * + * @param Horde_Group_DataTreeObject $group The new group object. + * + * @throws Horde_Group_Exception + * @throws Horde_History_Exception + * @throws InvalidArgumentException + */ + public function addGroup(Horde_Group_DataTreeObject $group) + { + $result = $this->_datatree->add($group); + if ($result instanceof PEAR_Error) { + throw new Horde_Group_Exception($result); + } + + $id = $group->getId(); + $name = $group->getName(); + $this->_groupCache[$name] = &$group; + $this->_groupMap[$id] = $name; + if (isset($this->_groupList)) { + $this->_groupList[$id] = $name; + } + + /* Log the addition of the group in the history log. */ + $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'add'), true); + + return $result; + } + + /** + * Stores updated data - users, etc. - of a group to the backend system. + * + * @param Horde_Group_DataTreeObject $group The group to update. + * + * @throws Horde_History_Exception + * @throws InvalidArgumentException + */ + public function updateGroup(Horde_Group_DataTreeObject $group) + { + $result = $this->_datatree->updateData($group); + if ($result instanceof PEAR_Error) { + return $result; + } + + $this->_groupCache[$group->getName()] = &$group; + + /* Log the update of the group users on the history log. */ + $history = $GLOBALS['injector']->getInstance('Horde_History'); + $guid = $this->getGUID($group); + foreach ($group->getAuditLog() as $userId => $action) { + $history->log($guid, array('action' => $action, 'user' => $userId), true); + } + $group->clearAuditLog(); + + /* Log the group modification. */ + $history->log($guid, array('action' => 'modify'), true); + + return $result; + } + + /** + * Removes a group from the groups system permanently. + * + * @param Horde_Group_DataTreeObject $group The group to remove. + * @param boolean $force Force to remove every child? + * + * @throws Horde_History_Exception + * @throws InvalidArgumentException + */ + public function removeGroup(Horde_Group_DataTreeObject $group, + $force = false) + { + $id = $group->getId(); + unset($this->_groupMap[$id]); + if (isset($this->_groupList)) { + unset($this->_groupList[$id]); + } + unset($this->_groupCache[$group->getName()]); + + $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'delete'), true); + + return $this->_datatree->remove($group, $force); + } + + /** + * Retrieves the name of a group. + * + * @param integer|Horde_Group_DataTreeObject $gid The id of the group or + * the group object to + * retrieve the name for. + * + * @return string The group's name. + */ + public function getGroupName($gid) + { + if ($gid instanceof Horde_Group_DataTreeObject) { + $gid = $gid->getId(); + } + + if (isset($this->_groupMap[$gid])) { + return $this->_groupMap[$gid]; + } + if (isset($this->_groupList[$gid])) { + return $this->_groupList[$gid]; + } + + return $this->_datatree->getName($gid); + } + + /** + * Strips all parent references off of the given group name. + * + * @param string $group Name of the group. + * + * @return The name of the group without parents. + */ + public function getGroupShortName($group) + { + return $this->_datatree->getShortName($group); + } + + /** + * Retrieves the ID of a group. + * + * @param integer|Horde_Group_DataTreeObject $gid The id of the group or + * the group object to + * retrieve the ID for. + * + * @return integer The group's ID. + */ + public function getGroupId($group) + { + if ($group instanceof Horde_Group_DataTreeObject) { + $group = $group->getName(); + } + + $id = array_search($group, $this->_groupMap); + if ($id !== false) { + return $id; + } + + if (isset($this->_groupList)) { + $id = array_search($group, $this->_groupList); + if ($id !== false) { + return $id; + } + } + + return $this->_datatree->getId($group); + } + + /** + * Check if a group exists in the system. + * + * @param string $group The group to check. + * + * @return boolean True if the group exists, false otherwise. + */ + public function exists($group) + { + if (isset($this->_groupCache[$group]) || + (isset($this->_groupList) && + array_search($group, $this->_groupList) !== false)) { + return true; + } + + return $this->_datatree->exists($group); + } + + /** + * Returns a tree of the parents of a child group. + * + * @param integer $gid The id of the child group. + * + * @return array The group parents tree, with groupnames as the keys. + * @throws Horde_Group_Exception + */ + public function getGroupParents($gid) + { + if (!isset($this->_parentTree[$gid])) { + $name = $this->getGroupName($gid); + $parents = $this->_datatree->getParents($name); + if ($parents instanceof PEAR_Error) { + throw new Horde_Group_Exception($parents); + } + $this->_parentTree[$gid] = $parents; + } + + return $this->_parentTree[$gid]; + } + + /** + * Returns the single parent ID of the given group. + * + * @param integer $gid The DataTree ID of the child group. + * + * @return integer The parent of the given group. + * @throws Horde_Group_Exception + */ + public function getGroupParent($gid) + { + if (!isset($this->_groupParents[$gid])) { + $parent = $this->_datatree->getParentById($gid); + if ($parent instanceof PEAR_Error) { + throw new Horde_Group_Exception($parent); + } + $this->_groupParents[$gid] = $parent; + } + + return $this->_groupParents[$gid]; + } + + /** + * Returns a flat list of the parents of a child group + * + * @param integer $gid The id of the group. + * + * @return array A flat list of all of the parents of $group, hashed in + * $id => $name format. + * @throws Horde_Group_Exception + */ + public function getGroupParentList($gid) + { + if (!isset($this->_groupParentList[$gid])) { + $parents = $this->_datatree->getParentList($gid); + if ($parents instanceof PEAR_Error) { + throw new Horde_Group_Exception($parents); + } + $this->_groupParentList[$gid] = $parents; + } + + return $this->_groupParentList[$gid]; + } + + /** + * Returns a list of all groups, in the format id => groupname. + * + * @param boolean $refresh If true, the cached value is ignored and the + * group list is refreshed from the group backend. + * + * @return array ID => groupname hash. + */ + public function listGroups($refresh = false) + { + if ($refresh || !isset($this->_groupList)) { + $this->_groupList = $this->_datatree->get(DATATREE_FORMAT_FLAT, GROUP_ROOT, true); + unset($this->_groupList[GROUP_ROOT]); + } + + return $this->_groupList; + } + + /** + * Get a list of every user that is a part of this group ONLY. + * + * @param integer $gid The ID of the group. + * + * @return array The user list. + * @throws Horde_Group_Exception + */ + public function listUsers($gid) + { + $groupOb = $this->getGroupById($gid); + + if (!isset($groupOb->data['users']) || + !is_array($groupOb->data['users'])) { + return array(); + } + + return array_keys($groupOb->data['users']); + } + + /** + * Get a list of every user that is part of the specified group + * and any of its subgroups. + * + * @param integer $group The ID of the parent group. + * + * @return array The complete user list. + * @throws Horde_Group_Exception + */ + public function listAllUsers($gid) + { + if (!isset($this->_subGroups[$gid])) { + // Get a list of every group that is a sub-group of $group. + $groups = $this->_datatree->get(DATATREE_FORMAT_FLAT, $this->getGroupName($gid), true); + if ($groups instanceof PEAR_Error) { + throw new Horde_Group_Exception($groups); + } + $this->_subGroups[$gid] = array_keys($groups); + } + + $users = array(); + foreach ($this->_subGroups[$gid] as $groupId) { + $users = array_merge($users, $this->listUsers($groupId)); + } + + return array_values(array_flip(array_flip($users))); + } + + /** + * Get a list of every group that $user is in. + * + * @param string $user The user to get groups for. + * @param boolean $parentGroups Also return the parents of any groups? + * + * @return array An array of all groups the user is in. + * @throws Horde_Group_Exception + */ + public function getGroupMemberships($user, $parentGroups = false) + { + if (!isset($this->_userGroups[$user])) { + $criteria = array( + 'AND' => array( + array('field' => 'name', 'op' => '=', 'test' => 'user'), + array('field' => 'key', 'op' => '=', 'test' => $user))); + $groups = $this->_datatree->getByAttributes($criteria); + if ($groups instanceof PEAR_Error) { + throw new Horde_Group_Exception($groups); + } + + if ($parentGroups) { + foreach ($groups as $id => $g) { + $parents = $this->_datatree->getParentList($id); + if ($parents instanceof PEAR_Error) { + throw new Horde_Group_Exception($parents); + } + $groups += $parents; + } + } + + $this->_userGroups[$user] = $groups; + } + + return $this->_userGroups[$user]; + } + + /** + * Say if a user is a member of a group or not. + * + * @param string $user The name of the user. + * @param integer $gid The ID of the group. + * @param boolean $subgroups Return true if the user is in any subgroups + * of group with ID $gid, also. + * + * @return boolean + */ + public function userIsInGroup($user, $gid, $subgroups = true) + { + if (!$this->exists($this->getGroupName($gid))) { + return false; + } elseif ($subgroups) { + try { + $groups = $this->getGroupMemberships($user, true); + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); + return false; + } + + return !empty($groups[$gid]); + } else { + try { + $users = $this->listUsers($gid); + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); + return false; + } + return in_array($user, $users); + } + } + + /** + * Returns the nesting level of the given group. 0 is returned for any + * object directly below self::ROOT. + * + * @param integer $gid The DataTree ID of the group. + * + * @return The DataTree level of the group. + */ + public function getLevel($gid) + { + return substr_count($this->getGroupName($gid), ':'); + } + +} diff --git a/framework/Group/lib/Horde/Group/ContactListObject.php b/framework/Group/lib/Horde/Group/ContactListObject.php new file mode 100644 index 000000000..a95b997aa --- /dev/null +++ b/framework/Group/lib/Horde/Group/ContactListObject.php @@ -0,0 +1,127 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_ContactListObject extends DataTreeObject_Group +{ + + /** + * The unique name of this object. + * These names have the same requirements as other object names - they + * must be unique, etc. + * + * @var string + */ + protected $name; + + /** + * The unique name of this object. + * These names have the same requirements as other object names - they + * must be unique, etc. + * + * @var integer + */ + protected $id; + + /** + * Key-value hash that will be serialized. + * + * @see getData() + * @var array + */ + protected $data = array(); + + /** + * Constructor. + * + * @param string $name The name of the group. + */ + public function __construct($name) + { + $this->name = $name; + } + + /** + * Gets the ID of this object. + * + * @return string The object's ID. + */ + public function getId() + { + return $this->id; + } + + /** + * Gets the name of this object. + * + * @return string The object name. + */ + public function getName() + { + return $this->name; + } + + /** + * 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) + { + return isset($this->data[$attribute]) + ? $this->data[$attribute] + : null; + } + + /** + * Sets one of the attributes of the object. + * + * @param string $attribute The attribute to set. + * @param mixed $value The value for $attribute. + * + * @throws Horde_Group_Exception + */ + public function set($attribute, $value) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Save group. + * + * @throws Horde_Group_Exception + */ + public function save() + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * @throws Horde_Group_Exception + */ + public function removeUser($username, $update = true) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * @throws Horde_Group_Exception + */ + function addUser($username, $update = true) + { + throw new Horde_Group_Exception('Unsupported.'); + } + +} diff --git a/framework/Group/lib/Horde/Group/Contactlists.php b/framework/Group/lib/Horde/Group/Contactlists.php new file mode 100644 index 000000000..3bb70e25f --- /dev/null +++ b/framework/Group/lib/Horde/Group/Contactlists.php @@ -0,0 +1,614 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_Contactlists extends Horde_Group +{ + /** + * A cache object + * + * @var Horde_Cache object + */ + protected $_cache = null; + + /** + * Handles for the database connections. Need one for each possible + * source. + * + * @var DB + */ + protected $_db = array(); + + /** + * Local copy of available address book sources that the group driver can + * use. + * + * @var array of Turba's cfgSource style entries. + */ + protected $_sources = array(); + + /** + * Local cache of retreived group entries from Turba storage. + * + * @var unknown_type + */ + protected $_listEntries = array(); + + /** + * Constructor. + */ + public function __construct(array $params = array()) + { + // Get a list of all available Turba sources + $turba_sources = Horde::loadConfiguration('sources.php', + 'cfgSources', 'turba'); + + // We only support sql type sources. + foreach ($turba_sources as $key => $source) { + if ($source['type'] == 'sql') { + $this->_sources[$key] = $source; + } + } + + $this->_cache = $GLOBALS['injector']->getInstance('Horde_Cache'); + } + + /** + * Initializes the object. + */ + public function __wakeup() + { + } + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + } + + /** + * Stores the object in the session cache. + */ + public function shutdown() + { + } + + /** + * Returns a new group object. + * + * @param string $name The group's name. + * @param string $parent The group's parent's name. + * + * @throws Horde_Group_Exception + */ + public function newGroup($name, $parent = GROUP_ROOT) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Returns a Group object corresponding to the named group, + * with the users and other data retrieved appropriately. + * + * This is deprecated. Use getGroupById() instead. + * + * @param string $name The name of the group to retrieve. + * @throws Horde_Group_Exception + */ + public function getGroup($name) + { + throw new Horde_Group_Exception('Deprecated. Use getGroupById() instead.'); + } + + /** + * Returns a Horde_Group_ContactListObject object corresponding to the + * given unique ID, with the users and other data retrieved + * appropriately. + * + * @param integer $cid The unique ID of the group to retrieve. + * + * @return Horde_Group_ContactListObject + * @throws Horde_Group_Exception + */ + public function getGroupById($gid) + { + if (!empty($this->_groupCache[$gid])) { + return $this->_groupCache[$gid]; + } + + list($source, $id) = explode(':', $gid); + $entry = $this->_retrieveListEntry($gid); + if (empty($entry)) { + throw new Horde_Group_Exception($gid . ' does not exist'); + } + + $users = $this->_getAllMembers($gid); + + $group = new Horde_Group_ContactListObject($entry[$this->_sources[$source]['map'][$this->_sources[$source]['list_name_field']]]); + $group->id = $gid; + $group->data['email'] = $entry[$this->_sources[$source]['map']['email']]; + if (!empty($users)) { + $group->data['users'] = array_flip($users); + } + + $group->setGroupOb($this); + $this->_groupCache[$gid] = $group; + + return $group; + } + + /** + * Adds a group to the groups system. The group must first be created with + * newGroup(), and have any initial users added to it, before this + * function is called. + * + * @param Horde_Group_ContactListObject $group The new group object. + * @throws Horde_Group_Exception + */ + public function addGroup($group) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Stores updated data - users, etc. - of a group to the backend system. + * + * @param ContactListObject_Group $group The group to update. + * + * @throws Horde_Group_Exception + */ + public function updateGroup($group) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Removes a group from the groups system permanently. + * + * @param ContactListObject_Group $group The group to remove. + * @param boolean $force Force to remove every child. + * + * @throws Horde_Group_Exception + */ + public function removeGroup($group, $force = false) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Retrieves the name of a group. + * + * @param integer|Horde_Group_ContactListObject $gid The id of the group + * or the group object + * to retrieve the name + * for. + * + * @return string The group's name. + * @throws Horde_Group_Exception + */ + public function getGroupName($gid) + { + static $beenHere; + + if (strpos($gid, ':') === false) { + throw new Horde_Group_Exception(sprintf('Group %s not found.', $gid)); + } + + if ($gid instanceof Horde_Group_ContactListObject) { + $gid = $gid->getId(); + } + + if (!empty($this->_listEntries[$gid])) { + list($source, $id) = explode(':', $gid); + $beenHere = false; + return $this->_listEntries[$gid][$this->_sources[$source]['map'][$this->_sources[$source]['list_name_field']]]; + } + + $this->_retrieveListEntry($gid); + + // We should have the information cached now, try again..but protect + // against anything nasty... + if (!$beenHere) { + $beenHere = true; + return $this->getGroupName($gid); + } + + throw new Horde_Group_Exception(sprintf('Group %s not found.', $gid)); + } + + /** + * Strips all parent references off of the given group name. + * Not used in this driver...group display names are ONLY for display. + * + * @param string $group Name of the group. + * + * @return string The name of the group without parents. + */ + public function getGroupShortName($group) + { + return $group; + } + + /** + * Retrieves the ID of a group, given the group object. + * Here for BC. Kinda silly, since if we have the object, we can just call + * getId() ourselves. + * + * @param ContactListObject_Group $group The group object to retrieve the + * ID for. + * + * @return integer The group's ID. + * @throws Horde_Group_Exception + */ + public function getGroupId($group) + { + if ($group instanceof Horde_Group_ContactListObject) { + return $group->getId(); + } + + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Check if a group exists in the system. + * This must either be a noop or we need to somehow "uniqueify" the + * list's display name? + * + * @param string $group The group name to check. + * + * @return boolean True if the group exists, false otherwise. + */ + public function exists($group) + { + return true; + } + + /** + * Returns a tree of the parents of a child group. + * + * @param integer $gid The id of the child group. + * + * @return array The group parents tree, with groupnames as the keys. + */ + public function getGroupParents($gid) + { + return array(); + } + + /** + * Returns the single parent ID of the given group. + * + * @param integer $gid The ID of the child group. + * + * @return integer The parent of the given group. + */ + public function getGroupParent($gid) + { + return self::ROOT; + } + + /** + * Returns a flat list of the parents of a child group + * + * @param integer $gid The id of the group. + * + * @return array A flat list of all of the parents of $group, hashed in + * $id => $name format. + */ + public function getGroupParentList($gid) + { + return array(); + } + + /** + * Returns a list of all groups, in the format id => groupname. + * The groups returned represent only the groups visible to the current + * user only. + * + * @param boolean $refresh If true, the cached value is ignored and the + * group list is refreshed from the group backend. + * + * @return array ID => groupname hash. + */ + public function listGroups($refresh = false) + { + if (isset($this->_groupList) && !$refresh) { + return $this->_groupList; + } + + // First, make sure we are connected to all sources + $this->_connect(); + + $groups = $owners = array(); + + foreach ($this->_sources as $key => $source) { + if ($source['use_shares']) { + if (empty($contact_shares)) { + $scope = $GLOBALS['registry']->hasInterface('contacts'); + $shares = $GLOBALS['injector']->getInstance('Horde_Share')->getScope($scope); + $this->_contact_shares = $shares->listShares(Horde_Auth::getAuth(), Horde_Perms::SHOW, Horde_Auth::getAuth()); + } + // Contruct a list of owner ids to use + foreach ($this->_contact_shares as $id => $share) { + $params = @unserialize($share->get('params')); + if ($params['source'] == $key) { + $owners[] = $params['name']; + } + } + } else { + $owners = array(Horde_Auth::getAuth()); + } + $owner_ids = array(); + foreach ($owners as $owner) { + $owner_ids[] = $this->_db[$key]->quote($owner); + } + $sql = 'SELECT ' . $source['map']['__key'] . ', ' . $source['map'][$source['list_name_field']] + . ' FROM ' . $source['params']['table'] . ' WHERE ' + . $source['map']['__type'] . ' = \'Group\' AND ' + . $source['map']['__owner'] . ' IN (' . implode(',', $owner_ids ) . ')'; + + $results = $this->_db[$key]->getAssoc($sql); + foreach ($results as $id => $name) { + $groups[$key . ':' . $id] = $name; + } + } + $this->_groupList = $groups; + + return $this->_groupList; + } + + /** + * Get a list of every user that is part of the specified group + * and any of its subgroups. + * + * @param integer $group The ID of the parent group. + * + * @return array The complete user list. + * @throws Horde_Group_Exception + */ + public function listAllUsers($gid) + { + return array_values($this->_getAllMembers($gid, true)); + } + + /** + * Returns a hash representing the list entry. Items are keyed by the + * backend specific keys. + * + * @param string $gid The group id. + * + * @return array + * @throws Horde_Group_Exception + */ + protected function _retrieveListEntry($gid) + { + if (!empty($this->_listEntries[$gid])) { + return $this->_listEntries[$gid]; + } + + list($source, $id) = explode(':', $gid); + if (empty($this->_sources[$source])) { + return array(); + } + + $this->_connect($source); + $sql = 'SELECT ' . $this->_sources[$source]['map']['__members'] . ',' + . $this->_sources[$source]['map']['email'] . ',' + . $this->_sources[$source]['map'][$this->_sources[$source]['list_name_field']] + . ' from ' . $this->_sources[$source]['params']['table'] . ' WHERE ' + . $this->_sources[$source]['map']['__key'] . ' = ' . $this->_db[$source]->quote($id); + + $results = $this->_db[$source]->getRow($sql, array(), DB_FETCHMODE_ASSOC); + if ($results instanceof PEAR_Error) { + Horde::logMessage($results, 'ERR'); + throw new Horde_Group_Exception($results); + } + $this->_listEntries[$gid] = $results; + + return $results; + } + + /** + * TODO + * + * @throws Horde_Group_Exception + */ + protected function _getAllMembers($gid, $subGroups = false) + { + if (empty($gid) || strpos($gid, ':') === false) { + throw new Horde_Group_Exception(sprintf('Unsupported group id: %s', $gid)); + } + + list($source, $id) = explode(':', $gid); + $entry = $this->_retrieveListEntry($gid); + $members = @unserialize($entry[$this->_sources[$source]['map']['__members']]); + $users = array(); + + // TODO: optimize this to only query each table once + foreach ($members as $member) { + // Is this member from the same source or a different one? + if (strpos($member, ':') !== false) { + list($newSource, $uid) = explode(':', $member); + if (!empty($this->_contact_shares[$newSource])) { + $params = @unserialize($this->_contact_shares[$newSource]->get('params')); + $newSource = $params['source']; + $member = $uid; + $this->_connect($newSource); + } elseif (empty($this->_sources[$newSource])) { + // Last chance, it's not in one of our non-share sources + continue; + } + } else { + // Same source + $newSource = $source; + } + + $sql = 'SELECT ' . $this->_sources[$newSource]['map']['email'] + . ', ' . $this->_sources[$newSource]['map']['__type'] + . ' FROM ' . $this->_sources[$newSource]['params']['table'] + . ' WHERE ' . $this->_sources[$newSource]['map']['__key'] + . ' = ' . $this->_db[$newSource]->quote($member); + + $results = $this->_db[$newSource]->getRow($sql); + if ($results instanceof PEAR_Error) { + Horde::logMessage($results, 'ERR'); + throw new Horde_Group_Exception($results); + } + + // Sub-Lists are treated as sub groups the best that we can... + if ($subGroups && $results[1] == 'Group') { + $this->_subGroups[$gid] = $newSource . ':' . $member; + $users = array_merge($users, $this->_getAllMembers($newSource . ':' . $member)); + } + if (strlen($results[0])) { + // use a key to dump dups + $users[$results[0]] = $results[0]; + } + } + + return $users; + } + + /** + * Returns ALL contact lists present in ALL sources that this driver knows + * about. + * + * @throws Horde_Group_Exception + */ + protected function _listAllLists() + { + // Clear the cache - we will rebuild it. + $this->_listEntries = array(); + + foreach ($this->_sources as $key => $source) { + $this->_connect($key); + $sql = 'SELECT ' . $source['map']['__key'] . ',' + . $source['map']['__members'] . ',' + . $source['map']['email'] . ',' + . $source['map'][$source['list_name_field']] + . ' FROM ' . $source['params']['table'] . ' WHERE ' + . $source['map']['__type'] . ' = \'Group\''; + + $results = $this->_db[$key]->query($sql); + if ($results instanceof PEAR_Error) { + throw new Horde_Group_Exception($results); + } + + while ($row = $results->fetchRow(DB_FETCHMODE_ASSOC)) { + $this->_listEntries[$key . ':' . $row[$source['map']['__key']]] = $row; + } + } + + return $this->_listEntries; + } + + /** + * Get a list of every group that $user is in. + * + * @param string $user The user to get groups for. + * @param boolean $parentGroups Also return the parents of any groups? + * + * @return array An array of all groups the user is in. + */ + public function getGroupMemberships($user, $parentGroups = false) + { + if (($memberships = $this->_cache->get('Group_contactlists_memberships' . md5($user))) !== false) { + return unserialize($memberships); + } + $lists = $this->_listAllLists(); + $memberships = array(); + foreach (array_keys($lists) as $list) { + $members = $this->_getAllMembers($list, $parentGroups); + if (!empty($members[$user])) { + $memberships[] = $list; + } + } + + $this->_cache->set('Group_contactlists_memberships' . md5($user), serialize($memberships)); + + return $memberships; + } + + /** + * Say if a user is a member of a group or not. + * + * @param string $user The name of the user. + * @param integer $gid The ID of the group. + * @param boolean $subgroups Return true if the user is in any subgroups + * of group with ID $gid, also. + * + * @return boolean + */ + public function userIsInGroup($user, $gid, $subgroups = true) + { + if (isset($_SESSION['horde']['groups']['i'][$user][$subgroups][$gid])) { + return $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid]; + } + + try { + $users = $this->_getAllMembers($gid, $subgroups); + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); + return false; + } + + $result = (bool)!empty($users[$user]); + $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid] = $result; + + return $result; + } + + /** + * Attempts to open a persistent connection to the sql server. + * + * @return boolean True on success. + * @throws Horde_Group_Exception + */ + protected function _connect($source = null) + { + if (!is_null($source) && !empty($this->_db[$source])) { + return; + } + + $sources = is_null($source) + ? array_keys($this->_sources) + : array($source); + + foreach ($sources as $source) { + if (empty($this->_db[$source])) { + $this->_db[$source] = DB::connect($this->_sources[$source]['params'], + array('persistent' => !empty($this->_sources[$source]['params']['persistent']))); + if ($this->_db[$source] instanceof PEAR_Error) { + throw new Horde_Group_Exception($this->_db[$source]); + } + + /* Set DB portability options. */ + switch ($this->_db[$source]->phptype) { + case 'mssql': + $this->_db[$source]->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); + break; + + default: + $this->_db[$source]->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); + } + } + } + + return true; + } + +} diff --git a/framework/Group/lib/Horde/Group/DataTreeObject.php b/framework/Group/lib/Horde/Group/DataTreeObject.php new file mode 100644 index 000000000..cd8b8e155 --- /dev/null +++ b/framework/Group/lib/Horde/Group/DataTreeObject.php @@ -0,0 +1,190 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_DataTreeObject extends DataTreeObject +{ + /** + * The Group object which this group is associated with - needed + * for updating data in the backend to make changes stick, etc. + * + * @var Horde_Group + */ + protected $_groupOb; + + /** + * This variable caches the users added or removed from the group + * for History logging of user-groups relationship. + * + * @var array + */ + protected $_auditLog = array(); + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + return array_diff(array_keys(get_class_vars(__CLASS__)), array('_datatree', '_groupOb')); + } + + /** + * Associates a group object with this group. + * + * @param Horde_Group $groupOb The group object. + */ + public function setGroupOb($groupOb) + { + $this->_groupOb = $groupOb; + } + + /** + * Fetch the ID of this group + * + * @return string The group's ID + */ + public function getId() + { + return $this->_groupOb->getGroupId($this); + } + + /** + * Save any changes to this object to the backend permanently. + */ + public function save() + { + return $this->_groupOb->updateGroup($this); + + } + + /** + * Adds a user to this group, and makes sure that the backend is + * updated as well. + * + * @param string $username The user to add. + */ + public function addUser($username, $update = true) + { + $this->data['users'][$username] = 1; + $this->_auditLog[$username] = 'addUser'; + if ($update && $this->_groupOb->exists($this->getName())) { + return $this->save(); + } + } + + /** + * Removes a user from this group, and makes sure that the backend + * is updated as well. + * + * @param string $username The user to remove. + */ + public function removeUser($username, $update = true) + { + unset($this->data['users'][$username]); + $this->_auditLog[$username] = 'deleteUser'; + if ($update) { + return $this->save(); + } + } + + /** + * Get a list of every user that is a part of this group + * (and only this group) + * + * @return array The user list. + */ + public function listUsers() + { + return $this->_groupOb->listUsers($this->getId()); + } + + /** + * Get a list of every user that is a part of this group and + * any of it's subgroups + * + * @return array The complete user list. + */ + public function listAllUsers() + { + return $this->_groupOb->listAllUsers($this->getId()); + } + + /** + * Get all the users recently added or removed from the group. + */ + public function getAuditLog() + { + return $this->_auditLog; + } + + /** + * Clears the audit log. To be called after group update. + */ + public function clearAuditLog() + { + $this->_auditLog = array(); + } + + /** + * Map this object's attributes from the data array into a format + * that we can store in the attributes storage backend. + * + * @return array The attributes array. + */ + protected function _toAttributes() + { + // Default to no attributes. + $attributes = array(); + + // Loop through all users, if any. + if (isset($this->data['users']) && is_array($this->data['users']) && count($this->data['users'])) { + foreach ($this->data['users'] as $user => $active) { + $attributes[] = array('name' => 'user', + 'key' => $user, + 'value' => $active); + } + } + $attributes[] = array('name' => 'email', + 'key' => '', + 'value' => $this->get('email')); + + return $attributes; + } + + /** + * Take in a list of attributes from the backend and map it to our + * internal data array. + * + * @param array $attributes The list of attributes from the + * backend (attribute name, key, and value). + */ + protected function _fromAttributes($attributes) + { + // Initialize data array. + $this->data['users'] = array(); + + foreach ($attributes as $attr) { + if ($attr['name'] == 'user') { + $this->data['users'][$attr['key']] = $attr['value']; + } else { + $this->data[$attr['name']] = $attr['value']; + } + } + } + +} diff --git a/framework/Group/lib/Horde/Group/Exception.php b/framework/Group/lib/Horde/Group/Exception.php new file mode 100644 index 000000000..e1265afcf --- /dev/null +++ b/framework/Group/lib/Horde/Group/Exception.php @@ -0,0 +1,17 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_Exception extends Horde_Exception_Prior +{ +} diff --git a/framework/Group/lib/Horde/Group/Hooks.php b/framework/Group/lib/Horde/Group/Hooks.php new file mode 100644 index 000000000..83ca1f014 --- /dev/null +++ b/framework/Group/lib/Horde/Group/Hooks.php @@ -0,0 +1,81 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_Hooks extends Horde_Group +{ + /** + * @var boolean + */ + protected $_hookFunction = false; + + /** + * Constructor. + * + * @params array $params + */ + public function __construct($params) + { + parent::__construct($params); + Horde::loadConfiguration('hooks.php', null, 'horde'); + $this->_hookFunction = function_exists('_group_hook'); + } + + /** + * Get a list of every group that $user is in. + * + * @param string $user The user to get groups for. + * @param boolean $parentGroups Also return the parents of any groups? + * + * @return array An array of all groups the user is in. + * @throws Horde_Group_Exception + */ + public function getGroupMemberships($user, $parentGroups = false) + { + $memberships = parent::getGroupMemberships($user, $parentGroups); + if (!$this->_hookFunction) { + return $memberships; + } + + $groups = $this->listGroups(); + foreach ($groups as $gid => $groupName) { + if (empty($memberships[$gid]) && _group_hook($groupName, $user)) { + $memberships += array($gid => $groupName); + } + + if ($parentGroups) { + $memberships += $this->getGroupParentList($gid); + } + } + + return $memberships; + } + + /** + * Say if a user is a member of a group or not. + * + * @param string $user The name of the user. + * @param integer $gid The ID of the group. + * @param boolean $subgroups Return true if the user is in any subgroups + * of $group, also. + * + * @return boolean + */ + public function userIsInGroup($user, $gid, $subgroups = true) + { + return ($this->_hookFunction && _group_hook($this->getGroupName($gid), $user)) || + parent::userIsInGroup($user, $gid, $subgroups); + } + +} diff --git a/framework/Group/lib/Horde/Group/Kolab.php b/framework/Group/lib/Horde/Group/Kolab.php new file mode 100644 index 000000000..c42864b73 --- /dev/null +++ b/framework/Group/lib/Horde/Group/Kolab.php @@ -0,0 +1,319 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_Kolab extends Horde_Group_Ldap +{ + /** + * Constructor. + * + * @throws Horde_Group_Exception + */ + public function __construct($params) + { + if (!function_exists('ldap_connect')) { + throw new Horde_Group_Exception('The Kolab group driver requires LDAP support.'); + } + + $this->_params = array( + 'hostspec' => $GLOBALS['conf']['kolab']['ldap']['server'], + 'basedn' => $GLOBALS['conf']['kolab']['ldap']['basedn'], + 'binddn' => $GLOBALS['conf']['kolab']['ldap']['phpdn'], + 'password' => $GLOBALS['conf']['kolab']['ldap']['phppw'], + 'version' => 3, + 'gid' => 'cn', + 'memberuid' => 'member', + 'attrisdn' => true, + 'filter_type' => 'objectclass', + 'objectclass' => 'kolabGroupOfNames', + 'newgroup_objectclass' => 'kolabGroupOfNames' + ); + + $this->_filter = 'objectclass=' . $this->_params['objectclass']; + + $this->__wakeup(); + } + + /** + * Initializes the object. + */ + public function __wakeup() + { + foreach (array_keys($this->_groupCache) as $name) { + $this->_groupCache[$name]->setGroupOb($this); + } + } + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + return array_diff(array_keys(get_class_vars(__CLASS__)), array('_datatree', '_ds')); + } + + /** + * Returns a new group object. + * + * @param string $name The group's name. + * @param string $parent The group's parent's name. + * + * @return Horde_Group_KolabObject A new group object. + * @throws Horde_Group_Exception + */ + public function newGroup($name) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Adds a group to the groups system. The group must first be created with + * newGroup(), and have any initial users added to it, before this + * function is called. + * + * @param Horde_Group_KolabObject $group The new group object. + * @throws Horde_Group_Exception + */ + public function addGroup($group) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Stores updated data - users, etc. - of a group to the backend system. + * + * @param Horde_Group_KolabObject $group The group to update. + * + * @throws Horde_Group_Exception + */ + public function updateGroup($group) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Removes a group from the groups system permanently. + * + * @param Horde_Group_KolabObject $group The group to remove. + * @param boolean $force Force to remove every child. + * + * @throws Horde_Group_Exception + */ + public function removeGroup($group, $force = false) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Return a Horde_Group_KolabObject corresponding to the given dn, with the + * users and other data retrieved appropriately. + * + * @param string $dn The dn of the group to retrieve. + * + * @return Horde_Group_KolabObject The requested group. + * @throws Horde_Group_Exception + */ + public function getGroupById($dn) + { + static $cache = array(); + + if (!isset($cache[$dn])) { + /* Connect to the LDAP server. */ + $success = $this->_connect(); + + $search = @ldap_search($this->_ds, $dn, $this->_filter); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + throw new Horde_Group_Exception('Empty result'); + } + + $attributes = array(); + for ($i = 0; $i < $result[0]['count']; $i++) { + if ($result[0][$result[0][$i]]['count'] > 1) { + $attributes[$result[0][$i]] = array(); + for ($j = 0; $j < $result[0][$result[0][$i]]['count']; $j++) { + $attributes[$result[0][$i]][] = $result[0][$result[0][$i]][$j]; + } + } else { + $attributes[$result[0][$i]] = $result[0][$result[0][$i]][0]; + } + } + $attributes['dn'] = $result[0]['dn']; + + $group = new Horde_Group_KolabObject($this->getGroupName($dn)); + $group->_fromAttributes($attributes); + $group->setGroupOb($this); + $cache[$dn] = $group; + } + + return $cache[$dn]; + } + + + /** + * Retrieve the ID of the given group. + * + * NOTE: If given a group name, this function can be unreliable if more + * than one group exists with the same name. + * + * @param mixed $group LDAP_Group object, or a group name (string) + * + * @return string The group's ID. + * @throws Horde_Group_Exception + */ + public function getGroupId($group) + { + static $cache = array(); + + if ($group instanceof Horde_Group_KolabObject) { + return $group->getDn(); + } + + if (!isset($cache[$group])) { + $this->_connect(); + $search = @ldap_search($this->_ds, $this->_params['basedn'], + $this->_params['gid'] . '=' . $group, + array($this->_params['gid'])); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + throw new Horde_Group_Exception('Empty result'); + } + $cache[$group] = $result[0]['dn']; + } + + return $cache[$group]; + } + + /** + * Get a list of the parents of a child group. + * + * @param string $dn The fully qualified group dn + * + * @return array Nested array of parents + */ + public function getGroupParents($dn) + { + return array(); + } + + /** + * Get the parent of the given group. + * + * @param string $dn The dn of the child group. + * + * @return string The dn of the parent group. + */ + public function getGroupParent($dn) + { + return null; + } + + /** + * Get a list of parents all the way up to the root object for the given + * group. + * + * @param string $dn The dn of the group. + * + * @return array A flat list of all of the parents of the given group, + * hashed in $dn => $name format. + */ + public function getGroupParentList($dn) + { + return array(); + } + + /** + * Tries to find a DN for a given kolab mail address. + * + * @param string $mail The mail address to search for. + * + * @return string The corresponding dn or false. + * @throws Horde_Group_Exception + */ + public function dnForMail($mail) + { + $filter = '(&(objectclass=kolabInetOrgPerson)(mail=' . Horde_Ldap::quote($mail) . '))'; + $search = @ldap_search($this->_ds, $this->_params['basedn'], $filter); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + $dn = @ldap_first_entry($this->_ds, $search); + if ($dn) { + return ldap_get_dn($this->_ds, $dn); + } + + throw new Horde_Group_Exception(sprintf('Error searching for user with the email address "%s"!', $mail)); + } + + /** + * Get a list of every group that the given user is a member of. + * + * @param string $user The user to get groups for. + * @param boolean $parentGroups Also return the parents of any groups? + * + * @return array An array of all groups the user is in. + * @throws Horde_Group_Exception + */ + public function getGroupMemberships($user, $parentGroups = false) + { + static $cache = array(); + + if (empty($cache[$user])) { + /* Connect to the LDAP server. */ + $success = $this->_connect(); + $dn = $this->dnForMail($user); + + // Set up search filter + $filter = '(' . $this->_params['memberuid'] . '=' . $dn . ')'; + + // Perform search + $search = @ldap_search($this->_ds, $this->_params['basedn'], $filter); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + return array(); + } + + $groups = array(); + $current_charset = Horde_Nls::getCharset(); + for ($i = 0; $i < $result['count']; $i++) { + $utf8_dn = Horde_String::convertCharset($result[$i]['dn'], 'UTF-8', $current_charset); + $groups[$utf8_dn] = $this->getGroupName($utf8_dn); + } + + $cache[$user] = $groups; + } + + return $cache[$user]; + } + +} diff --git a/framework/Group/lib/Horde/Group/KolabObject.php b/framework/Group/lib/Horde/Group/KolabObject.php new file mode 100644 index 000000000..c0264b960 --- /dev/null +++ b/framework/Group/lib/Horde/Group/KolabObject.php @@ -0,0 +1,162 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_KolabObject extends LDAP_Group +{ + /** + * Constructor. + * + * @param string $name The name of this group. + * @param string $parent The dn of the parent of this group. + */ + public function __construct($name, $parent = null) + { + $this->setName($name); + } + + /** + * Fetch the ID of this group + * + * @return string The group's ID + */ + public function getId() + { + return $this->getDn(); + } + + /** + * Save any changes to this object to the backend permanently. + * + * @throws Horde_Group_Exception + */ + public function save() + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Adds a user to this group, and makes sure that the backend is + * updated as well. + * + * @param string $username The user to add. + * + * @throws Horde_Group_Exception + */ + public function addUser($username, $update = true) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Removes a user from this group, and makes sure that the backend + * is updated as well. + * + * @param string $username The user to remove. + * + * @throws Horde_Group_Exception + */ + public function removeUser($username, $update = true) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Get all the users recently added or removed from the group. + */ + public function getAuditLog() + { + return array(); + } + + /** + * Clears the audit log. To be called after group update. + */ + public function clearAuditLog() + { + } + + /** + * Sets the name of this object. + * + * @param string $name The name to set this object's name to. + */ + public function getDn() + { + return $this->name . ',' . $GLOBALS['conf']['kolab']['ldap']['basedn']; + } + + /** + * Take in a list of attributes from the backend and map it to our + * internal data array. + * + * @param array $attributes The list of attributes from the backend. + */ + protected function _fromAttributes($attributes = array()) + { + $this->data['users'] = array(); + foreach ($attributes as $key => $value) { + if (Horde_String::lower($key) == 'member') { + if (is_array($value)) { + foreach ($value as $user) { + $pattern = '/^cn=([^,]+).*$/'; + $results = array(); + preg_match($pattern, $user, $results); + if (isset($results[1])) { + $user = $results[1]; + } + $this->data['users'][$user] = '1'; + } + } else { + $pattern = '/^cn=([^,]+).*$/'; + $results = array(); + preg_match($pattern, $value, $results); + if (isset($results[1])) { + $value = $results[1]; + } + $this->data['users'][$value] = '1'; + } + } elseif ($key == 'mail') { + $this->data['email'] = $value; + } else { + $this->data[$key] = $value; + } + } + } + + /** + * Map this object's attributes from the data array into a format that + * can be stored in an LDAP entry. + * + * @return array The entry array. + */ + protected function _toAttributes() + { + $attributes = array(); + foreach ($this->data as $key => $value) { + if ($key == 'users') { + foreach ($value as $user => $membership) { + $user = 'cn=' . $user . ',' . $GLOBALS['conf']['kolab']['ldap']['basedn']; + $attributes['member'][] = $user; + } + } elseif ($key == 'email') { + if (!empty($value)) { + $attributes['mail'] = $value; + } + } elseif ($key != 'dn' && $key != 'member') { + $attributes[$key] = !empty($value) ? $value : ' '; + } + } + + return $attributes; + } + +} diff --git a/framework/Group/lib/Horde/Group/Ldap.php b/framework/Group/lib/Horde/Group/Ldap.php new file mode 100644 index 000000000..919114f7a --- /dev/null +++ b/framework/Group/lib/Horde/Group/Ldap.php @@ -0,0 +1,692 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_Ldap extends Horde_Group +{ + /** + * LDAP connection handle + */ + protected $_ds; + + /** + * Local copy of the global $conf['group']['params'] array. Simply + * for coding convenience. + */ + protected $_params; + + /** + * Generated LDAP filter based on the config parameters + */ + protected $_filter; + + /** + * Constructor. + */ + public function __construct($params) + { + $this->_params = $GLOBALS['conf']['group']['params']; + + $this->_params['gid'] = Horde_String::lower($this->_params['gid']); + $this->_params['memberuid'] = Horde_String::lower($this->_params['memberuid']); + foreach ($this->_params['newgroup_objectclass'] as $key => $val) { + $this->_params['newgroup_objectclass'][$key] = Horde_String::lower($val); + } + + /* Generate LDAP search filter. */ + if (!empty($this->_params['filter'])) { + $this->_filter = $this->_params['filter']; + } elseif (!is_array($this->_params['objectclass'])) { + $this->_filter = 'objectclass=' . $this->_params['objectclass']; + } else { + $this->_filter = ''; + foreach ($this->_params['objectclass'] as $objectclass) { + $this->_filter = '(&' . $this->_filter; + $this->_filter .= '(objectclass=' . $objectclass . '))'; + } + } + + $this->_filter = Horde_String::lower($this->_filter); + } + + /** + * Connects to the LDAP server. + * + * @throws Horde_Group_Exception + */ + protected function _connect() + { + /* Connect to the LDAP server. */ + $this->_ds = @ldap_connect($this->_params['hostspec']); + if (!$this->_ds) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + if (!ldap_set_option($this->_ds, LDAP_OPT_PROTOCOL_VERSION, + $this->_params['version'])) { + Horde::logMessage( + sprintf('Set LDAP protocol version to %d failed: [%d] %s', + $this->_params['version'], + ldap_errno($conn), + ldap_error($conn), + __FILE__, __LINE__)); + } + + /* Start TLS if we're using it. */ + if (!empty($this->_params['tls'])) { + if (!@ldap_start_tls($this->_ds)) { + Horde::logMessage( + sprintf('STARTTLS failed: [%d] %s', + @ldap_errno($this->_ds), + @ldap_error($this->_ds)), + 'ERR'); + } + } + + if (isset($this->_params['binddn'])) { + $bind = @ldap_bind($this->_ds, $this->_params['binddn'], + $this->_params['password']); + } else { + $bind = @ldap_bind($this->_ds); + } + + if (!$bind) { + throw new Horde_Group_Exception('Could not bind to LDAP server'); + } + } + + /** + * Recursively deletes $dn. $this->_ds MUST already be connected. + * + * @throws Horde_Group_Exception + */ + protected function _recursive_delete($dn) + { + $search = @ldap_list($this->_ds, $dn, 'objectclass=*', array('')); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $children = @ldap_get_entries($this->_ds, $search); + for ($i = 0; $i < $children['count']; $i++) { + $result = $this->_recursive_delete($children[$i]['dn']); + if (!$result) { + throw new Horde_Group_Exception(sprintf(__CLASS__ . ': Unable to delete group "%s". This is what the server said: %s', $this->getName($children[$i]['dn']), @ldap_error($this->_ds))); + } + } + + if (!@ldap_delete($this->_ds, $dn)) { + throw new Horde_Group_Exception(sprintf(__CLASS__ . ': Unable to delete group "%s". This is what the server said: %s', $dn, @ldap_error($this->_ds))); + } + } + + /** + * Searches existing groups for the highest gidnumber, and returns + * one higher. + * + * @return integer + * + * @throws Horde_Group_Exception + */ + protected function _nextGid() + { + /* Connect to the LDAP server. */ + $this->_connect(); + + $search = @ldap_search($this->_ds, $this->_params['basedn'], $this->_filter); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + + if (!is_array($result) || (count($result) <= 1)) { + return 1; + } + + $nextgid = 0; + for ($i = 0; $i < $result['count']; $i++) { + if ($result[$i]['gidnumber'][0] > $nextgid) { + $nextgid = $result[$i]['gidnumber'][0]; + } + } + + return $nextgid + 1; + } + + /** + * Return a new group object. + * + * @param string $name The group's name. + * @param string $parent The group's parent's ID (DN). + * + * @return Horde_Group_LdapObject A new group object. + * @throws Horde_Exception + */ + public function newGroup(string $name, $parent = null) + { + try { + $entry = Horde::callHook('groupldap', array($name, $parent)); + } catch (Horde_Exception_HookNotSet $e) { + // Try this simple default and hope it works. + $entry[$this->_params['gid']] = $name; + $entry['objectclass'] = $this->_params['newgroup_objectclass']; + $entry['gidnumber'] = $this->_nextGid(); + } + + $group = new Horde_Group_LdapObject($name, $parent); + $group->_fromAttributes($entry); + $group->setGroupOb($this); + + return $group; + } + + /** + * Return a group object corresponding to the named group, with the + * users and other data retrieved appropriately. + * + * @param string $name The name of the group to retrieve. + * + * @return Horde_Group_LdapObject The requested group. + * @throws Horde_Group_Exception + */ + public function getGroup($name) + { + return $this->getGroupById($this->getGroupId($name)); + } + + /** + * Return a group object corresponding to the given dn, with the + * users and other data retrieved appropriately. + * + * @param string $dn The dn of the group to retrieve. + * + * @return Horde_Group_LdapObject The requested group. + * @throws Horde_Group_Exception + */ + public function getGroupById($dn) + { + static $cache = array(); + + if (!isset($cache[$dn])) { + /* Connect to the LDAP server. */ + $this->_connect(); + + $search = @ldap_search($this->_ds, $dn, $this->_filter); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + throw new Horde_Group_Exception('Empty result'); + } + + $attributes = array(); + for ($i = 0; $i < $result[0]['count']; $i++) { + if ($result[0][$result[0][$i]]['count'] > 1) { + $attributes[$result[0][$i]] = array(); + for ($j = 0; $j < $result[0][$result[0][$i]]['count']; $j++) { + $attributes[$result[0][$i]][] = $result[0][$result[0][$i]][$j]; + } + } else { + $attributes[$result[0][$i]] = $result[0][$result[0][$i]][0]; + } + } + $attributes['dn'] = $result[0]['dn']; + + $group = new Horde_Group_LdapObject($this->getGroupName($dn)); + $group->_fromAttributes($attributes); + $group->setGroupOb($this); + $cache[$dn] = $group; + } + + return $cache[$dn]; + } + + /** + * Get a globally unique ID for a group. This really just returns the dn + * for the group, but is included for compatibility with the Group class. + * + * @param Horde_Group_LdapObject $group The group. + * + * @return string A GUID referring to $group. + */ + public function getGUID($group) + { + return $group->get('dn'); + } + + /** + * Add a group to the groups system. The group must first be created with + * Group_ldap::newGroup(), and have any initial users added to it, before + * this function is called. + * + * @param Horde_Group_LdapObject $group The new group object. + * + * @throws Horde_Group_Exception + */ + public function addGroup(Horde_Group_DataTreeObject $group) + { + /* Connect to the LDAP server. */ + $this->_connect(); + + $dn = $group->get('dn'); + + $entry = $group->_toAttributes(); + $success = @ldap_add($this->_ds, $dn, $entry); + + if (!$success) { + throw new Horde_Group_Exception(sprintf(__CLASS__ . ': Unable to add group "%s". This is what the server said: ', $group->getName()) . @ldap_error($this->_ds)); + } + + @ldap_close($this->_ds); + } + + /** + * Store updated data - users, etc. - of a group to the backend system. + * + * @param Horde_Group_LdapObject $group The group to update + * + * @throws Horde_Group_Exception + * @throws Horde_History_Exception + * @throws InvalidArgumentException + */ + public function updateGroup(Horde_Group_DataTreeObject $group) + { + $entry = $group->_toAttributes(); + + /* Connect to the LDAP server. */ + $this->_connect(); + + // Do not attempt to change an LDAP object's objectClasses + unset($entry['objectclass']); + + $result = @ldap_modify($this->_ds, $group->getId(), $entry); + if (!$result) { + throw new Horde_Group_Exception(sprintf(__CLASS__ . ': Unable to update group "%s". This is what the server said: %s', $group->getName(), @ldap_error($this->_ds))); + } + + @ldap_close($this->_ds); + + /* Log the update of the group users on the history log. */ + $history = $GLOBALS['injector']->getInstance('Horde_History'); + $guid = $this->getGUID($group); + foreach ($group->getAuditLog() as $userId => $action) { + $history->log($guid, array('action' => $action, 'user' => $userId), true); + } + $group->clearAuditLog(); + + /* Log the group modification. */ + $history->log($guid, array('action' => 'modify'), true); + + return $result; + } + + /** + * Remove a group from the groups system permanently. + * + * @param Horde_Group_LdapObject $group The group to remove. + * @param boolean $force Recursively delete children groups if true. + * + * @throws Horde_Group_Exception + */ + public function removeGroup(Horde_Group_DataTreeObject $group, + $force = false) + { + $dn = $group->getId(); + + /* Connect to the LDAP server. */ + $this->_connect(); + + if ($force) { + return $this->_recursive_delete($dn); + } + + if (!@ldap_delete($this->_ds, $dn)) { + throw new Horde_Group_Exception(sprintf(__CLASS__ . ': Unable to delete group "%s". This is what the server said: %s', $dn, @ldap_error($this->_ds))); + } + } + + /** + * Retrieve the name of a group. + * + * @param string $dn The dn of the group to retrieve the name for. + * + * @return string The group's name. + * @throws Horde_Group_Exception + */ + public function getGroupName($dn) + { + $dn = Horde_String::convertCharset($dn, Horde_Nls::getCharset(), 'UTF-8'); + $result = @ldap_explode_dn($dn, 1); + if ($result === false) { + throw new Horde_Group_Exception('Invalid group ID passed (bad DN syntax)'); + } + + return $result[0]; + } + + /** + * DataTreeObject full names include references to parents, but LDAP does + * not have this concept. This function simply returns the $group + * parameter and is included for compatibility with the Group class. + * + * @param string $group Group name. + * + * @return string $group. + */ + public function getGroupShortName($group) + { + return $group; + } + + /** + * Retrieve the ID of the given group. + * + * NOTE: If given a group name, this function can be unreliable if more + * than one group exists with the same name. + * + * @param mixed $group Group object, or a group name (string). + * + * @return string The group's ID. + * @throws Horde_Group_Exception + */ + public function getGroupId($group) + { + static $cache = array(); + + if ($group instanceof Horde_Group_LdapObject) { + return $group->get('dn'); + } + + if (!isset($cache[$group])) { + $this->_connect(); + $search = @ldap_search($this->_ds, $this->_params['basedn'], + $this->_params['gid'] . '=' . $group, + array($this->_params['gid'])); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + throw new Horde_Group_Exception('Empty result'); + } + $cache[$group] = $result[0]['dn']; + } + + return $cache[$group]; + } + + /** + * Check if a group exists in the system. + * + * @param string $group The group name to check for. + * + * @return boolean True if the group exists, False otherwise. + * @throws Horde_Group_Exception + */ + public function exists($group) + { + static $cache = array(); + + if (!isset($cache[$group])) { + /* Connect to the LDAP server. */ + $this->_connect(); + + $groupDN = $this->getGroupId($group); + $group = $this->getGroupShortName($group); + + $res = @ldap_compare($this->_ds, $groupDN, $this->_params['gid'], $group); + if ($res === false) { + throw new Horde_Group_Exception(sprintf('Internal Error: An attribute must ALWAYS match itself: %s', @ldap_error($this->_ds))); + } + // $res is True if the group exists, -1 if not, false never + $cache[$group] = ($res === true); + } + + return $cache[$group]; + } + + /** + * Get a list of the parents of a child group. + * + * @param string $dn The fully qualified group dn + * + * @return array Nested array of parents + */ + public function getGroupParents($dn) + { + $parent = $this->getGroupParent($dn); + $parents = array(DATATREE_ROOT => 1); + while ($parent != DATATREE_ROOT) { + $parents = array($parent => $parents); + $parent = $this->getGroupParent($parent); + } + return $parents; + } + + /** + * Get the parent of the given group. + * + * @param string $dn The dn of the child group. + * + * @return string The dn of the parent group. + * @throws Horde_Group_Exception + */ + public function getGroupParent($dn) + { + if (@ldap_explode_dn($dn, 0) === false) { + throw new Horde_Group_Exception('Invalid group ID passed (bad DN syntax)'); + } + + unset($result['count'], $result[0]); + $parent_dn = implode(',', $result); + + return (Horde_String::lower($parent_dn) == Horde_String::lower($GLOBALS['conf']['group']['params']['basedn'])) + ? DATATREE_ROOT + : $parent_dn; + } + + /** + * Get a list of parents all the way up to the root object for the given + * group. + * + * @param string $dn The dn of the group. + * + * @return array A flat list of all of the parents of the given group, + * hashed in $dn => $name format. + * @throws Horde_Group_Exception + */ + public function getGroupParentList($dn) + { + if (@ldap_explode_dn($dn, 0) === false) { + throw new Horde_Group_Exception('Invalid group ID passed (bad DN syntax)'); + } + + $num = $result['count']; + unset($result['count'], $result[0]); + + $count = 0; + $parents = array(); + $parent_dn = implode(',', $result); + while ($parent_dn != $this->_params['basedn'] && $count++ != $num) { + $parents[$parent_dn] = $this->getGroupName($parent_dn); + unset($result[$count]); + $parent_dn = implode(',', $result); + } + $parents[DATATREE_ROOT] = DATATREE_ROOT; + + return $parents; + } + + /** + * Get a list of every group, in the format dn => groupname. + * + * @param boolean $refresh If true, the cached value is ignored and the + * group list is refreshed from the group backend. + * + * @return array dn => groupname hash. + * @throws Horde_Group_Exception + */ + public function listGroups($refresh = false) + { + static $groups; + + if ($refresh || is_null($groups)) { + /* Connect to the LDAP server. */ + $this->_connect(); + + $search = @ldap_search($this->_ds, $this->_params['basedn'], $this->_filter, array($this->_params['gid'])); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + @ldap_sort($this->_ds, $search, $this->_params['gid']); + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + return array(); + } + + $groups = array(); + for ($i = 0; $i < $result['count']; $i++) { + $groups[$result[$i]['dn']] = $this->getGroupName($result[$i]['dn']); + } + } + + return $groups; + } + + /** + * Get a list of every user that is part of the specified group and any + * of its subgroups. + * + * @param string $dn The dn of the parent group. + * + * @return array The complete user list. + * @throws Horde_Group_Exception + */ + public function listAllUsers($dn) + { + static $cache = array(); + + if (!isset($cache[$dn])) { + $this->_connect(); + + $search = @ldap_search($this->_ds, $dn, $this->_filter); + if (!$search) { + throw new Horde_Group_Exception(sprintf('Could not reach the LDAP server: %s', @ldap_error($this->_ds))); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + // Not an error, we just don't have any users in this group. + return array(); + } + + $users = array(); + for ($i = 0; $i < $result['count']; $i++) { + $users = array_merge($users, $this->listUsers($result[$i]['dn'])); + } + + $cache[$dn] = array_keys(array_flip($users)); + } + + return $cache[$dn]; + } + + /** + * Get a list of every group that the given user is a member of. + * + * @param string $user The user to get groups for. + * @param boolean $parentGroups Also return the parents of any groups? + * + * @return array An array of all groups the user is in. + * @throws Horde_Group_Exception + */ + public function getGroupMemberships($user, $parentGroups = false) + { + static $cache = array(); + + if (empty($cache[$user])) { + /* Connect to the LDAP server. */ + $this->_connect(); + + // Set up search filter + $filter = '(' . $this->_params['memberuid'] . '='; + if ($GLOBALS['conf']['group']['params']['attrisdn']) { + $filter .= $GLOBALS['conf']['auth']['params']['uid'] . '='; + } + $filter .= $user; + if ($GLOBALS['conf']['group']['params']['attrisdn']) { + $filter .= ',' . $GLOBALS['conf']['auth']['params']['basedn']; + } + $filter .= ')'; + + // Perform search + $search = @ldap_search($this->_ds, $this->_params['basedn'], $filter); + if (!$search) { + throw new Horde_Group_Exception('Could not reach the LDAP server'); + } + + $result = @ldap_get_entries($this->_ds, $search); + @ldap_close($this->_ds); + if (!is_array($result) || (count($result) <= 1)) { + return array(); + } + + $groups = array(); + $current_charset = Horde_Nls::getCharset(); + for ($i = 0; $i < $result['count']; $i++) { + $utf8_dn = Horde_String::convertCharset($result[$i]['dn'], 'UTF-8', $current_charset); + $groups[$utf8_dn] = $this->getGroupName($utf8_dn); + } + + $cache[$user] = $groups; + } + + return $cache[$user]; + } + + /** + * Returns the tree depth of the given group, relative to the base dn. + * 0 is returned for any object directly below the base dn. + * + * @param string $dn The dn of the object. + * + * @return intenger The tree depth of the group. + * @throws Horde_Group_Exception + */ + public function getLevel($dn) + { + $base = @ldap_explode_dn($this->_params['basedn'], 0); + if ($base === false) { + throw new Horde_Group_Exception('Invalid basedn configured'); + } + + $group = @ldap_explode_dn($dn, 0); + if ($group === false) { + throw new Horde_Group_Exception('Invalid group ID passed (bad DN syntax)'); + } + + return $group['count'] - $base['count'] - 1; + } + +} diff --git a/framework/Group/lib/Horde/Group/LdapObject.php b/framework/Group/lib/Horde/Group/LdapObject.php new file mode 100644 index 000000000..0ccd667ca --- /dev/null +++ b/framework/Group/lib/Horde/Group/LdapObject.php @@ -0,0 +1,129 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_LdapObject extends Horde_Group_DataTreeObject +{ + /** + * Constructor. + * + * @param string $name The name of this group. + * @param string $parent The dn of the parent of this group. + */ + public function __construct($name, $parent = null) + { + parent::__construct($name); + if ($parent) { + $this->data['dn'] = Horde_String::lower($GLOBALS['conf']['group']['params']['gid']) . '=' . $name . ',' . $parent; + } else { + $this->data['dn'] = Horde_String::lower($GLOBALS['conf']['group']['params']['gid']) . '=' . $name . + ',' . Horde_String::lower($GLOBALS['conf']['group']['params']['basedn']); + } + } + + /** + * Get a list of every user that is part of this group (and only + * this group). + * + * @return array The user list. + */ + public function listUsers() + { + return $this->_groupOb->listUsers($this->data['dn']); + } + + /** + * Get a list of every user that is a member of this group and any of + * it's subgroups. + * + * @return array The complete user list. + */ + public function listAllUsers() + { + return $this->_groupOb->listAllUsers($this->data['dn']); + } + + /** + * Take in a list of attributes from the backend and map it to our + * internal data array. + * + * @param array $attributes The list of attributes from the backend. + */ + protected function _fromAttributes($attributes = array()) + { + $this->data['users'] = array(); + foreach ($attributes as $key => $value) { + if (Horde_String::lower($key) == Horde_String::lower($GLOBALS['conf']['group']['params']['memberuid'])) { + if (is_array($value)) { + foreach ($value as $user) { + if ($GLOBALS['conf']['group']['params']['attrisdn']) { + $pattern = '/^' . $GLOBALS['conf']['auth']['params']['uid'] . '=([^,]+).*$/'; + $results = array(); + preg_match($pattern, $user, $results); + if (isset($results[1])) { + $user = $results[1]; + } + } + $this->data['users'][$user] = '1'; + } + } else { + if ($GLOBALS['conf']['group']['params']['attrisdn']) { + $pattern = '/^' . $GLOBALS['conf']['auth']['params']['uid'] . '=([^,]+).*$/'; + $results = array(); + preg_match($pattern, $value, $results); + if (isset($results[1])) { + $value = $results[1]; + } + } + $this->data['users'][$value] = '1'; + } + } elseif ($key == 'mail') { + $this->data['email'] = $value; + } else { + $this->data[$key] = $value; + } + } + } + + /** + * Map this object's attributes from the data array into a format that + * can be stored in an LDAP entry. + * + * @return array The entry array. + */ + protected function _toAttributes() + { + $attributes = array(); + foreach ($this->data as $key => $value) { + if ($key == 'users') { + foreach ($value as $user => $membership) { + if ($GLOBALS['conf']['group']['params']['attrisdn']) { + $user = $GLOBALS['conf']['auth']['params']['uid'] . + '=' . $user . ',' . $GLOBALS['conf']['auth']['params']['basedn']; + } + $attributes[Horde_String::lower($GLOBALS['conf']['group']['params']['memberuid'])][] = $user; + } + } elseif ($key == 'email') { + if (!empty($value)) { + $attributes['mail'] = $value; + } + } elseif ($key != 'dn' && $key != Horde_String::lower($GLOBALS['conf']['group']['params']['memberuid'])) { + $attributes[$key] = !empty($value) ? $value : ' '; + } + } + + return $attributes; + } + +} diff --git a/framework/Group/lib/Horde/Group/Mock.php b/framework/Group/lib/Horde/Group/Mock.php new file mode 100644 index 000000000..a3500fba1 --- /dev/null +++ b/framework/Group/lib/Horde/Group/Mock.php @@ -0,0 +1,291 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_Mock extends Horde_Group { + + /** + * Constructor. + */ + public function __construct() + { + } + + /** + * Initializes the object. + */ + public function __wakeup() + { + } + + /** + * Returns a new group object. + * + * @param string $name The group's name. + * @param string $parent The group's parent's name. + * + * @return DataTreeObject_Group A new group object. + * @throws Horde_Group_Exception + */ + public function newGroup($name, $parent = GROUP_ROOT) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Returns a DataTreeObject_Group object corresponding to the named group, + * with the users and other data retrieved appropriately. + * + * @param string $name The name of the group to retrieve. + * + * @throws Horde_Group_Exception + */ + public function getGroup($name) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Returns a group object corresponding to the given unique + * ID, with the users and other data retrieved appropriately. + * + * @param integer $cid The unique ID of the group to retrieve. + * + * @throws Horde_Group_Exception + */ + public function getGroupById($cid) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Adds a group to the groups system. The group must first be created with + * newGroup(), and have any initial users added to it, before this + * function is called. + * + * @param Horde_Group_DataTreeObject $group The new group object. + * + * @throws Horde_Group_Exception + */ + public function addGroup($group) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Stores updated data - users, etc. - of a group to the backend system. + * + * @param Horde_Group_DataTreeObject $group The group to update. + * + * @throws Horde_Group_Exception + */ + public function updateGroup($group) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Removes a group from the groups system permanently. + * + * @param Horde_Group_DataTreeObject $group The group to remove. + * @param boolean $force Force to remove every child. + * + * @throws Horde_Group_Exception + */ + public function removeGroup($group, $force = false) + { + throw new Horde_Group_Exception('Unsupported.'); + } + + /** + * Retrieves the name of a group. + * + * @param integer|Horde_Group_DataTreeObject $gid The id of the group or the + * group object to retrieve the + * name for. + * + * @return string The group's name. + */ + public function getGroupName($gid) + { + return ''; + } + + /** + * Strips all parent references off of the given group name. + * + * @param string $group Name of the group. + * + * @return The name of the group without parents. + */ + public function getGroupShortName($group) + { + return ''; + } + + /** + * Retrieves the ID of a group. + * + * @param string|Horde_Group_DataTreeObject $group The group name or object to + * retrieve the ID for. + * + * @return integer The group's ID. + */ + public function getGroupId($group) + { + return ''; + } + + /** + * Check if a group exists in the system. + * + * @param string $group The group to check. + * + * @return boolean True if the group exists, false otherwise. + */ + public function exists($group) + { + return false; + } + + /** + * Returns a tree of the parents of a child group. + * + * @param integer $gid The id of the child group. + * + * @return array The group parents tree, with groupnames as the keys. + */ + public function getGroupParents($gid) + { + return array(); + } + + /** + * Returns the single parent ID of the given group. + * + * @param integer $gid The DataTree ID of the child group. + * + * @return integer The parent of the given group. + */ + public function getGroupParent($gid) + { + return null; + } + + /** + * Returns a flat list of the parents of a child group + * + * @param integer $gid The id of the group. + * + * @return array A flat list of all of the parents of $group, hashed in + * $id => $name format. + */ + public function getGroupParentList($gid) + { + return array(); + } + + /** + * Returns a list of all groups, in the format id => groupname. + * + * @param boolean $refresh If true, the cached value is ignored and the + * group list is refreshed from the group backend. + * + * @return array ID => groupname hash. + */ + public function listGroups($refresh = false) + { + return array(); + } + + /** + * Get a list of every user that is a part of this group ONLY. + * + * @param integer $gid The ID of the group. + * + * @return array The user list. + */ + public function listUsers($gid) + { + return array(); + } + + /** + * Get a list of every user that is part of the specified group + * and any of its subgroups. + * + * @param integer $group The ID of the parent group. + * + * @return array The complete user list. + */ + public function listAllUsers($gid) + { + return array(); + } + + /** + * Get a list of every group that $user is in. + * + * @param string $user The user to get groups for. + * @param boolean $parentGroups Also return the parents of any groups? + * + * @return array An array of all groups the user is in. + */ + public function getGroupMemberships($user, $parentGroups = false) + { + return array(); + } + + /** + * Say if a user is a member of a group or not. + * + * @param string $user The name of the user. + * @param integer $gid The ID of the group. + * @param boolean $subgroups Return true if the user is in any subgroups + * of group with ID $gid, also. + * + * @return boolean + */ + public function userIsInGroup($user, $gid, $subgroups = true) + { + return false; + } + + /** + * Returns the nesting level of the given group. 0 is returned for any + * object directly below GROUP_ROOT. + * + * @param integer $gid The ID of the group. + * + * @return The nesting level of the group. + */ + public function getLevel($gid) + { + return 0; + } + + /** + * Stores the object in the session cache. + */ + public function shutdown() + { + } + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + } + +} diff --git a/framework/Group/lib/Horde/Group/Sql.php b/framework/Group/lib/Horde/Group/Sql.php new file mode 100644 index 000000000..31ee5aba9 --- /dev/null +++ b/framework/Group/lib/Horde/Group/Sql.php @@ -0,0 +1,710 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_Sql extends Horde_Group +{ + /** + * Handle for the current database connection. + * + * @var Horde_Db_Adapter_Base + */ + public $db; + + /** + * Constructor. + */ + public function __construct($params) + { + $this->_params = $params; + $this->db = $GLOBALS['injector']->getInstance('Horde_Db')->getOb('horde', 'group'); + } + + /** + * Initializes the object. + */ + public function __wakeup() + { + } + + /** + * Returns the properties that need to be serialized. + * + * @return array List of serializable properties. + */ + public function __sleep() + { + } + + /** + * Stores the object in the session cache. + */ + public function shutdown() + { + } + + /** + * Replace all occurences of ':' in an object name with '.'. + * + * @param string $name The name of the object. + * + * @return string The encoded name. + */ + public function encodeName($name) + { + return str_replace(':', '.', $name); + } + + /** + * Returns a new group object. + * + * @param string $name The group's name. + * @param string $parent The group's parent's name. + * + * @return Horde_Group_SqlObject A new group object. + */ + public function newGroup($name, $parent = self::ROOT) + { + if ($parent != self::ROOT) { + $name = $this->getGroupName($parent) . ':' . $this->encodeName($name); + } + + $group = new Horde_Group_SqlObject($name); + $group->setGroupOb($this); + + return $group; + } + + /** + * Returns a group object corresponding to the named group, + * with the users and other data retrieved appropriately. + * + * @param string $name The name of the group to retrieve. + * + * @throws Horde_Group_Exception + */ + public function getGroup($name) + { + if (!isset($this->_groupCache[$name])) { + $sql = 'SELECT group_uid, group_email FROM horde_groups WHERE group_name = ?'; + + try { + $group = $this->db->selectRow($sql, array($name)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + if (empty($group)) { + throw new Horde_Group_Exception($name . ' does not exist'); + } + + $sql = 'SELECT user_uid FROM horde_groups_members ' + . ' WHERE group_uid = ? ORDER BY user_uid ASC'; + + try { + $users = $this->db->selectValues($sql, array($group['group_uid'])); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + $object = new Horde_Group_SqlObject($name); + $object->id = $group['group_uid']; + $object->data['email'] = $group['group_email']; + + if (!empty($users)) { + $object->data['users'] = array_flip($users); + } + + $this->_groupCache[$name] = $object; + $this->_groupCache[$name]->setGroupOb($this); + $this->_groupMap[$this->_groupCache[$name]->getId()] = $name; + } + + return $this->_groupCache[$name]; + } + + /** + * Returns a group object corresponding to the given unique + * ID, with the users and other data retrieved appropriately. + * + * @param integer $cid The unique ID of the group to retrieve. + * + * @throws Horde_Group_Exception + */ + public function getGroupById($cid) + { + if (isset($this->_groupMap[$cid])) { + return $this->_groupCache[$this->_groupMap[$cid]]; + } + + $sql = 'SELECT group_name, group_email FROM horde_groups WHERE group_uid = ?'; + + try { + $row = $this->db->selectOne($sql, array($cid)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + if (empty($row)) { + throw new Horde_Group_Exception($cid . ' does not exist'); + } + + $sql = 'SELECT user_uid FROM horde_groups_members ' + . ' WHERE group_uid = ? ORDER BY user_uid ASC'; + + try { + $users = $this->db->selectValues($sql, array($cid)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + $group = new Horde_Group_SqlObject($row['group_name']); + $group->id = $cid; + $group->data['email'] = $row['group_email']; + + if (!empty($users)) { + $group->data['users'] = array_flip($users); + } + + $group->setGroupOb($this); + $name = $group->getName(); + $this->_groupCache[$name] = $group; + $this->_groupMap[$cid] = $name; + + return $group; + } + + /** + * Adds a group to the groups system. The group must first be created with + * newGroup(), and have any initial users added to it, before this + * function is called. + * + * @param Horde_Group_SqlObject $group The new group object. + * + * @throws Horde_Group_Exception + * @throws Horde_History_Exception + * @throws InvalidArgumentException + */ + public function addGroup(Horde_Group_SqlObject $group) + { + $group->setGroupOb($this); + $name = $group->getName(); + + $email = isset($group->data['email']) ? $group->data['email'] : ''; + + $query = 'INSERT INTO horde_groups (group_name, group_parents, group_email) VALUES (?, ?, ?)'; + + try { + $result = $this->db->insert($query, array($name, '', $email)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + $group->id = $result; + + if (!empty($group->data['users'])) { + $query = 'INSERT INTO horde_groups_members (group_uid, user_uid)' + .' VALUES (?, ?)'; + foreach ($group->data['users'] as $user) { + try { + $this->db->insert($query, array($result, $user)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + } + + $this->_groupCache[$name] = $group; + $this->_groupMap[$group_id] = $name; + if (isset($this->_groupList)) { + $this->_groupList[$group_id] = $name; + } + + /* Log the addition of the group in the history log. */ + $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'add'), true); + } + + /** + * Stores updated data - users, etc. - of a group to the backend system. + * + * @param Horde_Group_SqlObject $group The group to update. + * + * @throws Horde_Group_Exception + * @throws Horde_History_Exception + * @throws InvalidArgumentException + */ + public function updateGroup(Horde_Group_SqlObject $group) + { + $query = 'UPDATE horde_groups SET group_email = ? WHERE group_uid = ?'; + + try { + $this->db->update($query, array($this->data['email'], $this->id)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + $query = 'DELETE FROM horde_groups_members WHERE group_uid = ?'; + + try { + $this->db->delete($query, array($this->id)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + $query = 'INSERT INTO horde_groups_members (group_uid, user_uid)' . + ' VALUES (?, ?)'; + foreach ($this->data['users'] as $user) { + try { + $this->db->insert($query, array(intval($this->id), $user)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + + $this->_groupCache[$group->getName()] = &$group; + + /* Log the update of the group users on the history log. */ + $history = $GLOBALS['injector']->getInstance('Horde_History'); + $guid = $this->getGUID($group); + foreach ($group->getAuditLog() as $userId => $action) { + $history->log($guid, array('action' => $action, 'user' => $userId), true); + } + + $group->clearAuditLog(); + + /* Log the group modification. */ + $history->log($guid, array('action' => 'modify'), true); + + return $result; + } + + /** + * Removes a group from the groups system permanently. + * + * @param Horde_Group_SqlObject $group The group to remove. + * @param boolean $force Force to remove every child. + * + * @throws Horde_Group_Exception + * @throws Horde_History_Exception + * @throws InvalidArgumentException + */ + public function removeGroup(Horde_Group_SqlObject $group, $force = false) + { + $id = $group->getId(); + $name = $group->getName(); + unset($this->_groupMap[$id]); + if (isset($this->_groupList)) { + unset($this->_groupList[$id]); + } + unset($this->_groupCache[$name]); + + $GLOBALS['injector']->getInstance('Horde_History')->log($this->getGUID($group), array('action' => 'delete'), true); + + $query = 'DELETE FROM horde_groups_members WHERE group_uid = ?'; + + try { + $this->db->delete($query, array($id)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + $query = 'DELETE FROM horde_groups WHERE group_uid = ?'; + try { + $this->db->delete($query, array($id)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + if ($force) { + $query = 'DELETE FROM horde_groups WHERE group_name LIKE ?'; + + try { + $this->db->delete($query, array($name . ':%')); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + } + + /** + * Retrieves the name of a group. + * + * @param integer|Horde_Group_SqlObject $gid The id of the group or the + * group object to retrieve the + * name for. + * + * @return string The group's name. + * @throws Horde_Group_Exception + */ + public function getGroupName($gid) + { + if ($gid instanceof Horde_Group_SqlObject) { + $gid = $gid->getId(); + } + + if (isset($this->_groupMap[$gid])) { + return $this->_groupMap[$gid]; + } + if (isset($this->_groupList[$gid])) { + return $this->_groupList[$gid]; + } + + $query = 'SELECT group_name FROM horde_groups WHERE group_uid = ?'; + + try { + return $this->db->selectValue($query, $gid); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + + /** + * Strips all parent references off of the given group name. + * + * @param string $group Name of the group. + * + * @return The name of the group without parents. + */ + public function getGroupShortName($group) + { + /* If there are several components to the name, explode and get the + * last one, otherwise just return the name. */ + if (strpos($group, ':') !== false) { + $name = explode(':', $group); + return array_pop($name); + } + + return $group; + } + + /** + * Retrieves the ID of a group. + * + * @param string|Horde_Group_SqlObject $group The group name or object to + * retrieve the ID for. + * + * @return integer The group's ID. + * @throws Horde_Group_Exception + */ + public function getGroupId($group) + { + if ($group instanceof Horde_Group_SqlObject) { + return $group->getId(); + } + + $id = array_search($group, $this->_groupMap); + if ($id !== false) { + return $id; + } + if (isset($this->_groupList)) { + $id = array_search($group, $this->_groupList); + if ($id !== false) { + return $id; + } + } + + $query = 'SELECT group_uid FROM horde_groups WHERE group_name = ?'; + + try { + return $this->db->selectValue($query, $group); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + + /** + * Check if a group exists in the system. + * + * @param string $group The group to check. + * + * @return boolean True if the group exists, false otherwise. + */ + public function exists($group) + { + if (isset($this->_groupCache[$group]) || + (isset($this->_groupList) && + array_search($group, $this->_groupList) !== false)) { + return true; + } + + $query = 'SELECT COUNT(*) FROM horde_groups WHERE group_name = ?'; + + try { + return (bool)$this->db->selectValue($query, $group); + } catch (Horde_Db_Exception $e) { + return false; + } + } + + /** + * Returns a tree of the parents of a child group. + * + * @param integer $gid The id of the child group. + * + * @return array The group parents tree, with groupnames as the keys. + * @throws Horde_Group_Exception + */ + function getGroupParents($gid) + { + if (!isset($this->_parentTree[$gid])) { + $name = $this->getGroupName($gid); + $this->_parentTree[$gid] = $this->_getGroupParents($name); + } + + return $this->_parentTree[$gid]; + } + + /** + * 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. + */ + protected function _getGroupParents($child) + { + if (($pos = strrpos($child, ':')) !== false) { + $child = substr($child, 0, $pos); + } + + return $this->_getParents($child); + } + + /** + */ + protected function _getParents($parents) + { + $mother = array(); + if (!empty($parents)) { + $pname = $parents; + $parents = substr($parents, 0, strrpos($parents, ':')); + $mother[$pname] = $this->_getParents($parents); + } else { + return array(self::ROOT => true); + } + + return $mother; + } + + /** + * Returns the single parent ID of the given group. + * + * @param integer $gid The ID of the child group. + * + * @return integer The parent of the given group. + */ + public function getGroupParent($gid) + { + if (!isset($this->_groupParents[$gid])) { + $name = $this->getGroupName($gid); + if (($pos = strrpos($name, ':')) !== false) { + $this->_groupParents[$gid] = $this->getGroupId(substr($name, 0, $pos)); + } else { + $this->_groupParents[$gid] = self::ROOT; + } + } + + return $this->_groupParents[$gid]; + } + + /** + * Returns a flat list of the parents of a child group + * + * @param integer $gid The id of the group. + * + * @return array A flat list of all of the parents of $group, hashed in + * $id => $name format. + *@throws Horde_Group_Exception + */ + public function getGroupParentList($gid) + { + if (!isset($this->_groupParentList[$gid])) { + $name = $this->getGroupName($gid); + $pos = strpos($name, ':'); + if ($pos == false) { + $this->_groupParentList[$gid] = array(); + return $this->_groupParentList[$gid]; + } + + $parents = array(); + while ($pos) { + $name = substr($name, 0, $pos); + $parents[] = $name; + $pos = strpos($name, ':'); + } + + $query = 'SELECT group_uid, group_name FROM horde_groups ' + . ' WHERE group_name IN (' . str_repeat('?, ', count($parents) - 1) . '?) '; + try { + $this->_groupParentList[$gid] = $this->db->selectAssoc($query, $parents); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + + return $this->_groupParentList[$gid]; + } + + /** + * Returns a flat list of the parents of a child group + * + * @param integer $gid The id of the group. + * + * @return array A flat list of all of the parents of $group, hashed in + * $id => $name format. + */ + protected function _getGroupParentNameList($name) + { + $parents = array(); + + while ($pos) { + $name = substr($name, 0, $pos); + $parents[] = $name; + $pos = strpos($name, ':'); + } + + return $parents; + } + + /** + * Returns a list of all groups, in the format id => groupname. + * + * @param boolean $refresh If true, the cached value is ignored and the + * group list is refreshed from the group backend. + * + * @return array ID => groupname hash. + * @throws Horde_Group_Exception + */ + public function listGroups($refresh = false) + { + if ($refresh || !isset($this->_groupList)) { + $sql = 'SELECT group_uid, group_name FROM horde_groups ORDER BY group_uid'; + try { + $this->_groupList = $this->db->selectAssoc($sql); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + + return $this->_groupList; + } + + /** + * Get a list of every user that is part of the specified group + * and any of its subgroups. + * + * @param integer $group The ID of the parent group. + * + * @return array The complete user list. + * @throws Horde_Group_Exception + */ + public function listAllUsers($gid) + { + if (!isset($this->_subGroups[$gid])) { + // Get a list of every group that is a sub-group of $group. + $name = $this->getGroupName($gid); + $query = 'SELECT group_uid FROM horde_groups WHERE group_name LIKE ?'; + + try { + $this->_subGroups[$gid] = $this->db->selectValues($query, array($name . ':%')); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + $this->_subGroups[$gid][] = $gid; + } + + $users = array(); + foreach ($this->_subGroups[$gid] as $groupId) { + $users = array_merge($users, $this->listUsers($groupId)); + } + + return array_values(array_flip(array_flip($users))); + } + + /** + * Get a list of every group that $user is in. + * + * @param string $user The user to get groups for. + * @param boolean $parentGroups Also return the parents of any groups? + * + * @return array An array of all groups the user is in. + * @throws Horde_Group_Exception + */ + public function getGroupMemberships($user, $parentGroups = false) + { + if (isset($_SESSION['horde']['groups']['m'][$user][$parentGroups])) { + return $_SESSION['horde']['groups']['m'][$user][$parentGroups]; + } + + $sql = 'SELECT g.group_uid AS group_uid, g.group_name AS group_name FROM horde_groups g, horde_groups_members m ' + . ' WHERE m.user_uid = ? AND g.group_uid = m.group_uid ORDER BY g.group_name'; + try { + $result = $this->db->selectAll($sql, $user); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + $groups = array(); + foreach ($result as $row) { + $groups[(int)$row['group_uid']] = $this->getGroupShortName($row['group_name']); + } + + if ($parentGroups) { + foreach ($groups as $id => $g) { + $groups += $this->getGroupParentList($id); + } + } + + $_SESSION['horde']['groups']['m'][$user][$parentGroups] = $groups; + + return $groups; + } + + /** + * Say if a user is a member of a group or not. + * + * @param string $user The name of the user. + * @param integer $gid The ID of the group. + * @param boolean $subgroups Return true if the user is in any subgroups + * of group with ID $gid, also. + * + * @return boolean + */ + public function userIsInGroup($user, $gid, $subgroups = true) + { + if (isset($_SESSION['horde']['groups']['i'][$user][$subgroups][$gid])) { + return $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid]; + } + + if ($subgroups) { + try { + $groups = $this->getGroupMemberships($user, true); + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); + return false; + } + + $result = !empty($groups[$gid]); + } else { + $query = 'SELECT COUNT(*) FROM horde_groups_members WHERE group_uid = ? AND user_uid = ?'; + try { + $result = $this->db->selectValue($query, array($gid, $user)); + } catch (Horde_Db_Exception $e) { + $result = false; + } + + } + + $_SESSION['horde']['groups']['i'][$user][$subgroups][$gid] = (bool)$result; + return (bool)$result; + } + +} diff --git a/framework/Group/lib/Horde/Group/SqlObject.php b/framework/Group/lib/Horde/Group/SqlObject.php new file mode 100644 index 000000000..e37be8fdf --- /dev/null +++ b/framework/Group/lib/Horde/Group/SqlObject.php @@ -0,0 +1,133 @@ + + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package Group + */ +class Horde_Group_SqlObject extends Horde_Group_DataTreeObject +{ + /** + * The unique name of this object. + * These names have the same requirements as other object names - they must + * be unique, etc. + * + * @var string + */ + public $name; + + /** + * The unique name of this object. + * These names have the same requirements as other object names - they must + * be unique, etc. + * + * @var integer + */ + public $id; + + /** + * Key-value hash that will be serialized. + * + * @see getData() + * @var array + */ + public $data = array(); + + /** + * Constructor. + * + * @param string $name The name of the group. + */ + public function __construct($name) + { + $this->name = $name; + } + + /** + * Gets the ID of this object. + * + * @return string The object's ID. + */ + public function getId() + { + return $this->id; + } + + /** + * Gets the name of this object. + * + * @return string The object name. + */ + public function getName() + { + return $this->name; + } + + /** + * 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 get($attribute) + { + return isset($this->data[$attribute]) + ? $this->data[$attribute] + : null; + } + + /** + * Sets one of the attributes of the object. + * + * @param string $attribute The attribute to set. + * @param mixed $value The value for $attribute. + */ + public set($attribute, $value) + { + $this->data[$attribute] = $value; + } + + /** + * Save group + * + * @throws Horde_Group_Exception + */ + public function save() + { + if (isset($this->data['email'])) { + $query = 'UPDATE horde_groups SET group_email = ? WHERE group_uid = ?'; + try { + $this->_groupOb->db->update($query, array($this->data['email'], $this->id)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + + $query = 'DELETE FROM horde_groups_members WHERE group_uid = ?'; + + try { + $this->_groupOb->db->delete($query, array($this->id)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + + if (!empty($this->data['users'])) { + $query = 'INSERT INTO horde_groups_members (group_uid, user_uid)' . + ' VALUES (?, ?)'; + foreach ($this->data['users'] as $user) { + try { + $this->db->insert($query, array(intval($this->id), $user)); + } catch (Horde_Db_Exception $e) { + throw new Horde_Group_Exception($e); + } + } + } + } + +} diff --git a/framework/Group/package.xml b/framework/Group/package.xml index 37f50daa7..faa8e20bd 100644 --- a/framework/Group/package.xml +++ b/framework/Group/package.xml @@ -20,72 +20,128 @@ http://pear.php.net/dtd/package-2.0.xsd"> jan@horde.org yes - 2008-09-16 + 2010-06-01 - 0.1.0 - 0.1.0 + 0.2.0 + 0.2.0 beta beta LGPL - * Added a mock driver for installations that don't need groups (Request #6157). -* Added a beta SQL Group driver (Request #6175). -* Removed unused renameGroup() function. -* Fixed loading subclasses before unserializing session objects (Bug #4650) -* Added caching. -* Fixed getGroupParents(). -* Fixed listAllUsers(). -* Switched from hook functions for every group to a single hook function for all groups (Request #4324). -* Added a Group driver for the Kolab groupware server. -* Allow group members to be stored as DNs in LDAP driver (Bug #4131). -* Significant changes to the LDAP Group driver (Bug #4135). -* Fixed chicken and egg problem for creating the first LDAP group (Bug #4668). -* Fixed nextgid calculation in the LDAP driver (Bug #4699). -* UTF-8-encoded DNs in the LDAP Groups driver (Bugs #4692 and #4918). + * Throw exceptions, not PEAR_Errors. + * Initial Horde 4 release. - - - - - - - - - + + + + + + + + + + + + + + + + + + + - 4.3.0 + 5.2.0 - 1.5.4 + 1.7.0 - Horde_Framework + Core pear.horde.org - Horde_DataTree + DataTree pear.horde.org - Auth + Exception pear.horde.org - - gettext - + + Util + pear.horde.org + + + + Auth + pear.horde.org + + + Db + pear.horde.org + + + Ldap + pear.horde.org + + - + + + + + + + + + + + + + + + + + + 2008-09-16 + + 0.1.0 + 0.1.0 + + + beta + beta + + LGPL + * Added a mock driver for installations that don't need groups (Request #6157). + * Added a beta SQL Group driver (Request #6175). + * Removed unused renameGroup() function. + * Fixed loading subclasses before unserializing session objects (Bug #4650) + * Added caching. + * Fixed getGroupParents(). + * Fixed listAllUsers(). + * Switched from hook functions for every group to a single hook function for all groups (Request #4324). + * Added a Group driver for the Kolab groupware server. + * Allow group members to be stored as DNs in LDAP driver (Bug #4131). + * Significant changes to the LDAP Group driver (Bug #4135). + * Fixed chicken and egg problem for creating the first LDAP group (Bug #4668). + * Fixed nextgid calculation in the LDAP driver (Bug #4699). + * UTF-8-encoded DNs in the LDAP Groups driver (Bugs #4692 and #4918). + + + 0.0.2 0.0.2 diff --git a/framework/Perms/lib/Horde/Perms.php b/framework/Perms/lib/Horde/Perms.php index d5899763a..45f75e40f 100644 --- a/framework/Perms/lib/Horde/Perms.php +++ b/framework/Perms/lib/Horde/Perms.php @@ -366,8 +366,7 @@ class Horde_Perms if (isset($permission->data['groups']) && is_array($permission->data['groups']) && count($permission->data['groups'])) { - require_once 'Horde/Group.php'; - $groups = Group::singleton(); + $groups = Horde_Group::singleton(); $composite_perm = null; $type = $permission->get('type'); diff --git a/framework/Share/lib/Horde/Share/Datatree.php b/framework/Share/lib/Horde/Share/Datatree.php index ccebe21da..9e973da3d 100644 --- a/framework/Share/lib/Horde/Share/Datatree.php +++ b/framework/Share/lib/Horde/Share/Datatree.php @@ -300,17 +300,18 @@ class Horde_Share_Datatree extends Horde_Share // If the user has any group memberships, check for those also. // @TODO: inject - require_once 'Horde/Group.php'; - $group = &Group::singleton(); - $groups = $group->getGroupMemberships($userid, true); - if (!($groups instanceof PEAR_Error) && $groups) { - // (name == perm_groups and key in ($groups) and val & $perm) - $criteria['OR'][] = array( - 'AND' => array( - array('field' => 'name', 'op' => '=', 'test' => 'perm_groups'), - array('field' => 'key', 'op' => 'IN', 'test' => array_keys($groups)), - array('field' => 'value', 'op' => '&', 'test' => $perm))); - } + try { + $group = Horde_Group::singleton(); + $groups = $group->getGroupMemberships($userid, true); + if ($groups) { + // (name == perm_groups and key in ($groups) and val & $perm) + $criteria['OR'][] = array( + 'AND' => array( + array('field' => 'name', 'op' => '=', 'test' => 'perm_groups'), +o array('field' => 'key', 'op' => 'IN', 'test' => array_keys($groups)), + array('field' => 'value', 'op' => '&', 'test' => $perm))); + } + } catch (Horde_Group_Exception $e) {} } else { $criteria = array( 'AND' => array( diff --git a/framework/Share/lib/Horde/Share/Sql.php b/framework/Share/lib/Horde/Share/Sql.php index def009f80..d919537c3 100644 --- a/framework/Share/lib/Horde/Share/Sql.php +++ b/framework/Share/lib/Horde/Share/Sql.php @@ -727,21 +727,22 @@ class Horde_Share_Sql extends Horde_Share // If the user has any group memberships, check for those also. // @TODO: Inject the group driver - require_once 'Horde/Group.php'; - $group = Group::singleton(); - $groups = $group->getGroupMemberships($userid, true); - if (!is_a($groups, 'PEAR_Error') && $groups) { - // (name == perm_groups and key in ($groups) and val & $perm) - $ids = array_keys($groups); - $group_ids = array(); - foreach ($ids as $id) { - $group_ids[] = $this->_db->quote((string)$id); + try { + $group = Horde_Group::singleton(); + $groups = $group->getGroupMemberships($userid, true); + if ($groups) { + // (name == perm_groups and key in ($groups) and val & $perm) + $ids = array_keys($groups); + $group_ids = array(); + foreach ($ids as $id) { + $group_ids[] = $this->_db->quote((string)$id); + } + $query .= ' LEFT JOIN ' . $this->_table . '_groups g ON g.share_id = s.share_id'; + $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')' + . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))'; } - $query .= ' LEFT JOIN ' . $this->_table . '_groups g ON g.share_id = s.share_id'; - $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')' - . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))'; - } elseif ($groups instanceof PEAR_Error) { - Horde::logMessage($groups, 'ERR'); + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); } } else { $where = '(' . Horde_SQL::buildClause($this->_db, 's.perm_guest', '&', $perm) . ')'; diff --git a/framework/Share/lib/Horde/Share/Sql/Hierarchical.php b/framework/Share/lib/Horde/Share/Sql/Hierarchical.php index e1d48e8d6..a379d1a8e 100644 --- a/framework/Share/lib/Horde/Share/Sql/Hierarchical.php +++ b/framework/Share/lib/Horde/Share/Sql/Hierarchical.php @@ -8,7 +8,7 @@ * @package Horde_Share */ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql -{ +{ /** * The Horde_Share_Object subclass to instantiate objects as * @@ -214,20 +214,21 @@ class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql // If the user has any group memberships, check for those also. // @TODO: Inject the group driver - require_once 'Horde/Group.php'; - $group = &Group::singleton(); - $groups = $group->getGroupMemberships($userid, true); - if (!($groups instanceof PEAR_Error) && $groups) { - // (name == perm_groups and key in ($groups) and val & $perm) - $ids = array_keys($groups); - $group_ids = array(); - foreach ($ids as $id) { - $group_ids[] = $this->_db->quote((string)$id); + try { + $group = Horde_Group::singleton(); + $groups = $group->getGroupMemberships($userid, true); + if ($groups) { + // (name == perm_groups and key in ($groups) and val & $perm) + $ids = array_keys($groups); + $group_ids = array(); + foreach ($ids as $id) { + $group_ids[] = $this->_db->quote((string)$id); + } + $query .= ' LEFT JOIN ' . $this->_table . '_groups AS g ON g.share_id = s.share_id'; + $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')' + . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))'; } - $query .= ' LEFT JOIN ' . $this->_table . '_groups AS g ON g.share_id = s.share_id'; - $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')' - . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))'; - } + } catch (Horde_Group_Exception $e) {} } } diff --git a/horde/admin/groups.php b/horde/admin/groups.php index f5220a414..7982dc303 100644 --- a/horde/admin/groups.php +++ b/horde/admin/groups.php @@ -11,8 +11,7 @@ require_once dirname(__FILE__) . '/../lib/Application.php'; Horde_Registry::appInit('horde', array('admin' => true)); -require_once 'Horde/Group.php'; -$groups = Group::singleton(); +$groups = Horde_Group::singleton(); $auth = $injector->getInstance('Horde_Auth')->getOb(); $form = null; @@ -22,92 +21,99 @@ $cid = Horde_Util::getFormData('cid'); switch ($actionID) { case 'addchild': - if ($cid == GROUP_ROOT) { + if ($cid == Horde_Group::ROOT) { $form = 'addchild.inc'; $gname = _("All Groups"); } else { - $group = &$groups->getGroupById($cid); - if (!is_a($group, 'PEAR_Error')) { + try { + $group = $groups->getGroupById($cid); $gname = $group->getShortName(); $form = 'addchild.inc'; - } + } catch (Horde_Group_Exception $e) {] } break; case 'addchildform': $parent = $cid; - if ($parent == GROUP_ROOT) { - $child = &$groups->newGroup(Horde_Util::getFormData('child')); - } else { - $child = &$groups->newGroup(Horde_Util::getFormData('child'), $parent); - } - if (is_a($child, 'PEAR_Error')) { - Horde::logMessage($child, 'ERR'); - $notification->push(sprintf(_("Group was not created: %s."), $child->getMessage()), 'horde.error'); + try { + $child = ($parent == Horde_Group::ROOT) + ? $groups->newGroup(Horde_Util::getFormData('child')) + : $groups->newGroup(Horde_Util::getFormData('child'), $parent); + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); + $notification->push(sprintf(_("Group was not created: %s."), $e->getMessage()), 'horde.error'); break; } - $result = $groups->addGroup($child); - if (is_a($result, 'PEAR_Error')) { - Horde::logMessage($result, 'ERR'); - $notification->push(sprintf(_("\"%s\" was not created: %s."), $child->getShortName(), $result->getMessage()), 'horde.error'); - } else { + try { + $groups->addGroup($child); $notification->push(sprintf(_("\"%s\" was added to the groups system."), $child->getShortName()), 'horde.success'); $group = $child; $form = 'edit.inc'; $reload = true; + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); + $notification->push(sprintf(_("\"%s\" was not created: %s."), $child->getShortName(), $e->getMessage()), 'horde.error'); } break; case 'delete': - $group = &$groups->getGroupById($cid); - if (!is_a($group, 'PEAR_Error')) { + try { + $group = $groups->getGroupById($cid); $form = 'delete.inc'; - } + } catch (Horde_Group_Exception $e) {} break; case 'deleteform': if (Horde_Util::getFormData('confirm') == _("Delete")) { - $group = &$groups->getGroupById($cid); - if (is_a($group, 'PEAR_Error')) { + try { + $group = $groups->getGroupById($cid); + } catch (Horde_Group_Exception $e) { $notification->push(_("Attempt to delete a non-existent group."), 'horde.error'); - } else { - $result = $groups->removeGroup($group, true); - if (is_a($result, 'PEAR_Error')) { - $notification->push(sprintf(_("Unable to delete \"%s\": %s."), $group->getShortName(), $result->getMessage()), 'horde.error'); - } else { - $notification->push(sprintf(_("Successfully deleted \"%s\"."), $group->getShortName()), 'horde.success'); - $cid = null; - $reload = true; - } + break; + } + + try { + $groups->removeGroup($group, true); + $notification->push(sprintf(_("Successfully deleted \"%s\"."), $group->getShortName()), 'horde.success'); + $cid = null; + $reload = true; + } catch (Horde_Group_Exception $e) { + $notification->push(sprintf(_("Unable to delete \"%s\": %s."), $group->getShortName(), $e->getMessage()), 'horde.error'); } } break; case 'edit': - $group = &$groups->getGroupById($cid); - if (!is_a($group, 'PEAR_Error')) { + try { + $group = $groups->getGroupById($cid); $form = 'edit.inc'; - } elseif (($category = Horde_Util::getFormData('category')) !== null) { - $group = &$groups->getGroup($category); - if (!is_a($group, 'PEAR_Error')) { + break; + } catch (Horde_Group_Exception $e) {} + + if (($category = Horde_Util::getFormData('category')) !== null) { + try { + $group = $groups->getGroup($category); $form = 'edit.inc'; - } elseif (Horde_Util::getFormData('autocreate')) { + break; + } catch (Horde_Group_Exception $e) {} + + if (Horde_Util::getFormData('autocreate')) { $parent = Horde_Util::getFormData('parent'); - $group = &$groups->newGroup($category); - $result = $groups->addGroup($group, $parent); - if (!is_a($result, 'PEAR_Error')) { + $group = $groups->newGroup($category); + try { + $groups->addGroup($group, $parent); $form = 'edit.inc'; - } + } catch (Horde_Group_Exception $e) {} } } break; case 'editform': - $group = &$groups->getGroupById($cid); + $group = $groups->getGroupById($cid); // make a copy of the group so we can restore it if there is an error. - $restore = $group; + $restore = clone $group; // Add any new users. $newuser = Horde_Util::getFormData('new_user'); @@ -133,14 +139,13 @@ case 'editform': $group->set('email', Horde_Util::getFormData('email')); // Save the group to the backend. - $result = $group->save(); - - if (is_a($result, 'PEAR_Error')) { - $notification->push($result->getMessage(), 'horde.error'); + try { + $group->save(); + $notification->push(sprintf(_("Updated \"%s\"."), $group->getShortName()), 'horde.success'); + } catch (Horde_Group_Exception $e) { + $notification->push($e, 'horde.error'); // restore backup copy $group = $restore; - } else { - $notification->push(sprintf(_("Updated \"%s\"."), $group->getShortName()), 'horde.success'); } $form = 'edit.inc'; @@ -155,22 +160,26 @@ case 'addchild.inc': case 'edit.inc': /* Set up the lists. */ - $users = $group->listUsers(); - if (is_a($users, 'PEAR_Error')) { - $notification->push($users, 'horde.error'); + try { + $users = $group->listUsers(); + } catch (Horde_Group_Exception $e) { + $notification->push($e, 'horde.error'); $users = array(); } - $all_users = $group->listAllUsers(); - if (is_a($all_users, 'PEAR_Error')) { - $notification->push($all_users, 'horde.error'); + + try { + $all_users = $group->listAllUsers(); + } catch (Horde_Group_Exception $e) { + $notification->push($e, 'horde.error'); $all_users = array(); } $inherited_users = array_diff($all_users, $users); if ($auth->hasCapability('list')) { - $user_list = $auth->listUsers(); - if (is_a($user_list, 'PEAR_Error')) { - $notification->push($user_list, 'horde.error'); + try { + $user_list = $auth->listUsers(); + } catch (Horde_Auth_Exception $e) { + $notification->push($e, 'horde.error'); $user_list = array(); } sort($user_list); @@ -190,10 +199,7 @@ if (!empty($form)) { /* Get the perms tree. */ $nodes = $groups->listGroups(true); -if (is_a($nodes, 'PEAR_Error')) { - throw new Horde_Exception_Prior($nodes); -} -$nodes[GROUP_ROOT] = GROUP_ROOT; +$nodes[Horde_Group::ROOT] = Horde_Group::ROOT; /* Set up some node params. */ $spacer = '    '; @@ -215,14 +221,11 @@ $tree->setHeader(array(array('width' => '50%'))); * for the root node. */ if ($cid > 0) { $cid_parents = $groups->getGroupParentList($cid); - if (is_a($cid_parents, 'PEAR_Error')) { - throw new Horde_Exception_Prior($cid_parents); - } } foreach ($nodes as $id => $node) { $node_params = ($cid == $id) ? array('class' => 'selected') : array(); - if ($id == GROUP_ROOT) { + if ($id == Horde_Group::ROOT) { $add_link = Horde::link(Horde_Util::addParameter($add, 'cid', $id), _("Add a new group")) . $add_img . ''; $base_node_params = $icondir + array('icon' => 'administration.png'); diff --git a/horde/lib/Api.php b/horde/lib/Api.php index ab8a9cc6c..1b399d47d 100644 --- a/horde/lib/Api.php +++ b/horde/lib/Api.php @@ -220,39 +220,40 @@ class Horde_Api extends Horde_Registry_Api } /* Remove user from all groups */ - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - $allGroups = $groups->getGroupMemberships($user); - if (is_a($groups, 'PEAR_Error')) { - Horde::logMessage($allGroups, 'ERR'); - $haveError = true; - } else { + $groups = Horde_Group::singleton(); + try { + $allGroups = $groups->getGroupMemberships($user); foreach (array_keys($allGroups) as $id) { $group = $groups->getGroupById($id); $group->removeUser($user, true); } + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); + $haveError = true; } /* Remove the user from all application permissions */ $perms = $GLOBALS['injector']->getInstance('Horde_Perms'); - $tree = $perms->getTree(); - if (is_a($tree, 'PEAR_Error')) { - Horde::logMessage($tree, 'ERR'); + try { + $tree = $perms->getTree(); + } catch (Horde_Perms_Exception $e) { + Horde::logMessage($e, 'ERR'); $haveError = true; - } else { - foreach (array_keys($tree) as $id) { + $tree = array(); + } + + foreach (array_keys($tree) as $id) { + try { $perm = $perms->getPermissionById($id); - if (is_a($perm, 'PEAR_Error')) { - Horde::logMessage($perm, 'ERR'); - $haveError = true; - continue; - } if ($perms->getPermissions($perm, $user)) { // The Horde_Perms::ALL is used if this is a matrix perm, // otherwise it's ignored in the method and the entry is // totally removed. $perm->removeUserPermission($user, Horde_Perms::ALL, true); } + } catch (Horde_Perms_Exception $e) { + Horde::logMessage($e, 'ERR'); + $haveError = true; } } @@ -314,19 +315,16 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to add groups.")); } - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - if (empty($parent)) { - $parent = GROUP_ROOT; - } - - if (is_a($group = &$groups->newGroup($name, $parent), 'PEAR_Error')) { - throw new Horde_Exception($group); + $parent = Horde_Group::ROOT; } - if (is_a($result = $groups->addGroup($group), 'PEAR_Error')) { - throw new Horde_Exception($result); + try { + $groups = Horde_Group::singleton(); + $group = $groups->newGroup($name, $parent); + $groups->addGroup($group); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } } @@ -343,15 +341,12 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to delete groups.")); } - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - - if (is_a($group = &$groups->getGroup($name), 'PEAR_Error')) { - throw new Horde_Exception($group); - } - - if (is_a($result = $groups->removeGroup($group, true), 'PEAR_Error')) { - throw new Horde_Exception($result); + try { + $groups = Horde_Group::singleton(); + $group = $groups->getGroup($name); + $groups->removeGroup($group, true); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } } @@ -369,15 +364,12 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to change groups.")); } - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - - if (is_a($group = &$groups->getGroup($name), 'PEAR_Error')) { - throw new Horde_Exception($group); - } - - if (is_a($result = $group->addUser($user), 'PEAR_Error')) { - throw new Horde_Exception($result); + try { + $groups = Horde_Group::singleton(); + $group = $groups->getGroup($name); + $group->addUser($user); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } } @@ -395,19 +387,15 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to change groups.")); } - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - - if (is_a($group = &$groups->getGroup($name), 'PEAR_Error')) { - throw new Horde_Exception($group); - } - - foreach ($users as $user) { - $group->addUser($user, false); - } - - if (is_a($result = $group->save(), 'PEAR_Error')) { - throw new Horde_Exception($result); + try { + $groups = Horde_Group::singleton(); + $group = $groups->getGroup($name); + foreach ($users as $user) { + $group->addUser($user, false); + } + $group->save(); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } } @@ -425,15 +413,12 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to change groups.")); } - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - - if (is_a($group = &$groups->getGroup($name), 'PEAR_Error')) { - throw new Horde_Exception($group); - } - - if (is_a($result = $group->removeUser($user), 'PEAR_Error')) { - throw new Horde_Exception($result); + try { + $groups = Horde_Group::singleton(); + $group = $groups->getGroup($name); + $group->removeUser($user); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } } @@ -451,21 +436,15 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to change groups.")); } - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - - if (is_a($group = &$groups->getGroup($name), 'PEAR_Error')) { - throw new Horde_Exception($group); - } - - foreach ($users as $user) { - if (is_a($result = $group->removeUser($user, false), 'PEAR_Error')) { - throw new Horde_Exception($result); + try { + $groups = Horde_Group::singleton(); + $group = $groups->getGroup($name); + foreach ($users as $user) { + $group->removeUser($user, false); } - } - - if (is_a($result = $group->save(), 'PEAR_Error')) { - throw new Horde_Exception($result); + $group->save(); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } } @@ -483,14 +462,13 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to list users of groups.")); } - require_once 'Horde/Group.php'; - $groups = Group::singleton(); - - if (is_a($group = &$groups->getGroup($name), 'PEAR_Error')) { - throw new Horde_Exception($group); + try { + $groups = Horde_Group::singleton(); + $group = $groups->getGroup($name); + return $group->listUsers(); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } - - return $group->listUsers(); } /* Shares. */ @@ -634,15 +612,17 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to change shares.")); } - require_once 'Horde/Group.php'; $shares = $GLOBALS['injector']->getInstance('Horde_Share')->getScope($scope); - $groups = Group::singleton(); if (is_a($share = &$shares->getShare($shareName), 'PEAR_Error')) { throw new Horde_Exception($share); } - if (is_a($groupId = $groups->getGroupId($groupName), 'PEAR_Error')) { - throw new Horde_Exception($groupId); + + try { + $groups = Horde_Group::singleton(); + $groupId = $groups->getGroupId($groupName); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } $perm = &$share->getPermission(); @@ -701,16 +681,17 @@ class Horde_Api extends Horde_Registry_Api throw new Horde_Exception(_("You are not allowed to change shares.")); } - require_once 'Horde/Group.php'; $shares = $GLOBALS['injector']->getInstance('Horde_Share')->getScope($scope); - $groups = Group::singleton(); if (is_a($share = &$shares->getShare($shareName), 'PEAR_Error')) { throw new Horde_Exception($share); } - if (is_a($groupId = $groups->getGroupId($groupName), 'PEAR_Error')) { - throw new Horde_Exception($groupId); + try { + $groups = Horde_Group::singleton(); + $groupId = $groups->getGroupId($groupName); + } catch (Horde_Group_Exception $e) { + throw new Horde_Exception($e); } if (is_a($result = $share->removeGroup($groupId), 'PEAR_Error')) { diff --git a/horde/scripts/sql/horde_groups.mysql.sql b/horde/scripts/sql/horde_groups.mysql.sql index 1b25018c5..868c0a7fe 100644 --- a/horde/scripts/sql/horde_groups.mysql.sql +++ b/horde/scripts/sql/horde_groups.mysql.sql @@ -1,5 +1,5 @@ CREATE TABLE horde_groups ( - group_uid INT(10) UNSIGNED NOT NULL, + group_uid INT(11) NOT NULL AUTO_INCREMENT, group_name VARCHAR(255) NOT NULL, group_parents VARCHAR(255) NOT NULL, group_email VARCHAR(255), @@ -8,8 +8,9 @@ CREATE TABLE horde_groups ( ); CREATE TABLE horde_groups_members ( - group_uid INT(10) UNSIGNED NOT NULL, + group_uid INT(11) NOT NULL, user_uid VARCHAR(255) NOT NULL ); + CREATE INDEX group_uid_idx ON horde_groups_members (group_uid); CREATE INDEX user_uid_idx ON horde_groups_members (user_uid); diff --git a/horde/scripts/sql/horde_groups.oci8.sql b/horde/scripts/sql/horde_groups.oci8.sql index 3f2c616a1..93025e8d3 100644 --- a/horde/scripts/sql/horde_groups.oci8.sql +++ b/horde/scripts/sql/horde_groups.oci8.sql @@ -13,3 +13,11 @@ CREATE TABLE horde_groups_members ( CREATE INDEX group_uid_idx ON horde_groups_members (group_uid); CREATE INDEX user_uid_idx ON horde_groups_members (user_uid); + +CREATE SEQUENCE horde_groups_uid_seq; +CREATE TRIGGER horde_groups_uid_trigger +BEFORE INSERT ON horde_groups +FOR EACH ROW +BEGIN + SELECT horde_groups_uid_seq.nextval INTO :new.group_uid FROM dual; +END; diff --git a/horde/scripts/sql/horde_groups.pgsql.sql b/horde/scripts/sql/horde_groups.pgsql.sql index b3d42ca0e..3ea74fa70 100644 --- a/horde/scripts/sql/horde_groups.pgsql.sql +++ b/horde/scripts/sql/horde_groups.pgsql.sql @@ -1,5 +1,5 @@ CREATE TABLE horde_groups ( - group_uid INTEGER NOT NULL, + group_uid SERIAL UNIQUE, group_name VARCHAR(255) NOT NULL UNIQUE, group_parents VARCHAR(255) NOT NULL, group_email VARCHAR(255), @@ -10,5 +10,6 @@ CREATE TABLE horde_groups_members ( group_uid INTEGER NOT NULL, user_uid VARCHAR(255) NOT NULL ); + CREATE INDEX group_uid_idx ON horde_groups_members (group_uid); CREATE INDEX user_uid_idx ON horde_groups_members (user_uid); diff --git a/horde/scripts/sql/horde_groups.sql b/horde/scripts/sql/horde_groups.sql index 99d1b7b9d..e12b22e76 100644 --- a/horde/scripts/sql/horde_groups.sql +++ b/horde/scripts/sql/horde_groups.sql @@ -1,5 +1,5 @@ CREATE TABLE horde_groups ( - group_uid INTEGER NOT NULL, + group_uid INTEGER NOT NULL AUTO_INCREMENT, group_name VARCHAR(255) NOT NULL, group_parents VARCHAR(255) NOT NULL, group_email VARCHAR(255), diff --git a/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.mysql.sql b/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.mysql.sql new file mode 100644 index 000000000..bbcfa91fa --- /dev/null +++ b/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.mysql.sql @@ -0,0 +1 @@ +ALTER TABLE horde_groups CHANGE COLUMN group_uid group_uid INT(11) NOT NULL AUTO_INCREMENT; diff --git a/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.oci8.sql b/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.oci8.sql new file mode 100644 index 000000000..00cd0b023 --- /dev/null +++ b/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.oci8.sql @@ -0,0 +1,7 @@ +CREATE SEQUENCE horde_group_uid_seq; +CREATE TRIGGER horde_group_uid_trigger +BEFORE INSERT ON horde_groups +FOR EACH ROW +BEGIN +SELECT horde_group_uid_seq.nextval INTO :new.group_uid FROM dual; +END; diff --git a/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.pgsql.sql b/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.pgsql.sql new file mode 100644 index 000000000..cd92611bc --- /dev/null +++ b/horde/scripts/upgrades/2010-06-01_horde_groups_autoincrement.pgsql.sql @@ -0,0 +1,2 @@ +CREATE SEQUENCE horde_group_uid_seq; +ALTER TABLE horde_groups ALTER COLUMN group_uid SET DEFAULT NEXTVAL('horde_group_uid_seq'); diff --git a/horde/scripts/upgrades/convert_datatree_groups_to_sql.php b/horde/scripts/upgrades/convert_datatree_groups_to_sql.php index 2db11d180..409fe1b4d 100755 --- a/horde/scripts/upgrades/convert_datatree_groups_to_sql.php +++ b/horde/scripts/upgrades/convert_datatree_groups_to_sql.php @@ -8,8 +8,7 @@ require_once dirname(__FILE__) . '/../../lib/Application.php'; Horde_Registry::appInit('horde', array('authentication' => 'none', 'cli' => true)); -require_once 'Horde/Group.php'; -$g = Group::factory(); +$g = Horde_Group::factory(); $group_query = ' INSERT INTO diff --git a/horde/services/shares/edit.php b/horde/services/shares/edit.php index 7a96b054f..edfe2bff3 100644 --- a/horde/services/shares/edit.php +++ b/horde/services/shares/edit.php @@ -11,8 +11,6 @@ require_once dirname(__FILE__) . '/../../lib/Application.php'; Horde_Registry::appInit('horde'); -require_once 'Horde/Group.php'; - // Exit if the user shouldn't be able to change share permissions. if (!empty($conf['share']['no_sharing'])) { throw new Horde_Exception('Permission denied.'); @@ -27,7 +25,7 @@ $fieldsList = array( $app = Horde_Util::getFormData('app'); $shares = $GLOBALS['injector']->getInstance('Horde_Share')->getScope($app); -$groups = Group::singleton(); +$groups = Horde_Group::singleton(); $auth = $injector->getInstance('Horde_Auth')->getOb(); if ($registry->hasMethod('shareHelp', $app)) { $help = $registry->callByPackage($app, 'shareHelp'); @@ -266,29 +264,27 @@ if (is_a($share, 'PEAR_Error')) { $title = sprintf(_("Edit permissions for \"%s\""), $share->get('name')); } +$userList = array(); if ($auth->hasCapability('list') && ($conf['auth']['list_users'] == 'list' || $conf['auth']['list_users'] == 'both')) { - $userList = $auth->listUsers(); - if ($userList instanceof PEAR_Error) { - Horde::logMessage($userList, 'ERR'); - $userList = array(); + try { + $userList = $auth->listUsers(); + sort($userList); + } catch (Horde_Auth_Exception $e) { + Horde::logMessage($e, 'ERR'); } - sort($userList); -} else { - $userList = array(); } -if (!empty($conf['share']['any_group'])) { - $groupList = $groups->listGroups(); -} else { - $groupList = $groups->getGroupMemberships(Horde_Auth::getAuth(), true); -} -if ($groupList instanceof PEAR_Error) { - Horde::logMessage($groupList, 'NOTICE'); +try { + $groupList = empty($conf['share']['any_group']) + ? $groups->getGroupMemberships(Horde_Auth::getAuth(), true) + : $groups->listGroups(); + asort($groupList); +} catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'NOTICE'); $groupList = array(); } -asort($groupList); require HORDE_TEMPLATES . '/common-header.inc'; $notification->notify(array('listeners' => 'status')); diff --git a/kronolith/lib/Api.php b/kronolith/lib/Api.php index a83fdd2e2..2b1080e4b 100644 --- a/kronolith/lib/Api.php +++ b/kronolith/lib/Api.php @@ -1133,14 +1133,12 @@ class Kronolith_Api extends Horde_Registry_Api */ public function listAlarms($time, $user = null) { - require_once 'Horde/Group.php'; - $current_user = Horde_Auth::getAuth(); if ((empty($user) || $user != $current_user) && !$GLOBALS['registry']->isAdmin()) { throw new Horde_Exception_PermissionDenied(); } - $group = Group::singleton(); + $group = Horde_Group::singleton(); $alarm_list = array(); $time = new Horde_Date($time); $calendars = is_null($user) ? array_keys($GLOBALS['kronolith_shares']->listAllShares()) : $GLOBALS['display_calendars']; @@ -1158,10 +1156,9 @@ class Kronolith_Api extends Horde_Registry_Api $users = $share->listUsers(Horde_Perms::READ); $groups = $share->listGroups(Horde_Perms::READ); foreach ($groups as $gid) { - $group_users = $group->listUsers($gid); - if (!($group_users instanceof PEAR_Error)) { - $users = array_merge($users, $group_users); - } + try { + $users = array_merge($users, $group->listUsers($gid)); + } catch (Horde_Group_Exception $e) {} } $users = array_unique($users); } else { diff --git a/kronolith/lib/Kronolith.php b/kronolith/lib/Kronolith.php index 157f20a9a..8fae6440e 100644 --- a/kronolith/lib/Kronolith.php +++ b/kronolith/lib/Kronolith.php @@ -1174,19 +1174,22 @@ class Kronolith $perm_value = Horde_Perms::READ | Horde_Perms::SHOW | Horde_Perms::EDIT | Horde_Perms::DELETE; break; } - $groups = &Group::singleton(); - $group_list = $groups->getGroupMemberships(Horde_Auth::getAuth()); - if (!($group_list instanceof PEAR_Error) && count($group_list)) { - $perm = $share->getPermission(); - // Add the default perm, not added otherwise - $perm->addUserPermission(Horde_Auth::getAuth(), Horde_Perms::ALL, false); - foreach ($group_list as $group_id => $group_name) { - $perm->addGroupPermission($group_id, $perm_value, false); + + try { + $groups = Horde_Group::singleton(); + $group_list = $groups->getGroupMemberships(Horde_Auth::getAuth()); + if (count($group_list)) { + $perm = $share->getPermission(); + // Add the default perm, not added otherwise + $perm->addUserPermission(Horde_Auth::getAuth(), Horde_Perms::ALL, false); + foreach ($group_list as $group_id => $group_name) { + $perm->addGroupPermission($group_id, $perm_value, false); + } + $share->setPermission($perm); + $share->save(); + $GLOBALS['notification']->push(sprintf(_("New calendar created and automatically shared with the following group(s): %s."), implode(', ', $group_list)), 'horde.success'); } - $share->setPermission($perm); - $share->save(); - $GLOBALS['notification']->push(sprintf(_("New calendar created and automatically shared with the following group(s): %s."), implode(', ', $group_list)), 'horde.success'); - } + } catch (Horde_Group_Exception $e) {} } $GLOBALS['prefs']->setValue('display_cals', serialize($GLOBALS['display_calendars'])); @@ -1833,7 +1836,7 @@ class Kronolith // Notify users that have been added. if ($GLOBALS['conf']['share']['notify'] && !isset($current[$group]) && $has_perms) { - $groupOb = Group::singleton()->getGroupById($group); + $groupOb = Horde_Group::singleton()->getGroupById($group); if (!empty($groupOb->data['email'])) { try { $message = Horde::callHook('shareGroupNotification', array($group, $share)); @@ -2261,9 +2264,7 @@ class Kronolith throw new Kronolith_Exception('Unknown event action: ' . $action); } - require_once 'Horde/Group.php'; - - $groups = Group::singleton(); + $groups = Horde_Group::singleton(); $calendar = $event->calendar; $recipients = array(); try { @@ -2287,15 +2288,14 @@ class Kronolith } foreach ($share->listGroups(Horde_Perms::READ) as $group) { - $group = $groups->getGroupById($group); - if ($group instanceof PEAR_Error) { - continue; - } - $group_users = $group->listAllUsers(); - if ($group_users instanceof PEAR_Error) { + try { + $group = $groups->getGroupById($group); + $group_users = $group->listAllUsers(); + } catch (Horde_Group_Exception $e) { Horde::logMessage($group_users, 'ERR'); continue; } + foreach ($group_users as $user) { if (!isset($recipients[$user])) { $recipients[$user] = self::_notificationPref($user, 'read', $calendar); diff --git a/kronolith/perms.php b/kronolith/perms.php index 187e65ec0..c38d40438 100644 --- a/kronolith/perms.php +++ b/kronolith/perms.php @@ -12,15 +12,13 @@ require_once dirname(__FILE__) . '/lib/Application.php'; Horde_Registry::appInit('kronolith'); -require_once 'Horde/Group.php'; - // Exit if the user shouldn't be able to change share permissions. if (!empty($conf['share']['no_sharing'])) { throw new Horde_Exception('Permission denied.'); } $shares = $GLOBALS['injector']->getInstance('Horde_Share')->getScope(); -$groups = Group::singleton(); +$groups = Horde_Group::singleton(); $auth = $injector->getInstance('Horde_Auth')->getOb(); $reload = false; @@ -100,16 +98,15 @@ if ($auth->hasCapability('list') && $userList = array(); } -if (!empty($conf['share']['any_group'])) { - $groupList = $groups->listGroups(); -} else { - $groupList = $groups->getGroupMemberships(Horde_Auth::getAuth(), true); -} -if ($groupList instanceof PEAR_Error) { - Horde::logMessage($groupList, 'NOTICE'); - $groupList = array(); +$groupList = array(); +try { + $groupList = empty($conf['share']['any_group']) + ? $groups->getGroupMemberships(Horde_Auth::getAuth(), true) + : $groups->listGroups(); + asort($groupList); +} catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'NOTICE'); } -asort($groupList); require KRONOLITH_TEMPLATES . '/common-header.inc'; $notification->notify(array('listeners' => 'status')); diff --git a/kronolith/templates/chunks/calendar.php b/kronolith/templates/chunks/calendar.php index d79f7dd65..7ce65a077 100644 --- a/kronolith/templates/chunks/calendar.php +++ b/kronolith/templates/chunks/calendar.php @@ -1,16 +1,15 @@ getInstance('Horde_Auth')->getOb(); -require_once 'Horde/Group.php'; -$horde_groups = Group::singleton(); -if (!empty($GLOBALS['conf']['share']['any_group'])) { - $groups = $horde_groups->listGroups(); -} else { - $groups = $horde_groups->getGroupMemberships(Horde_Auth::getAuth(), true); -} -if ($groups instanceof PEAR_Error) { - $groups = array(); -} -asort($groups); +$horde_groups = Horde_Group::singleton(); + +$groups = array(); +try { + $groups = empty($GLOBALS['conf']['share']['any_group']) + ? $horde_groups->getGroupMemberships(Horde_Auth::getAuth(), true) + : $horde_groups->listGroups(); + asort($groups); +} catch (Horde_Group_Exception $e) {} + $file_upload = $GLOBALS['browser']->allowFileUploads(); ?>
diff --git a/nag/lib/Api.php b/nag/lib/Api.php index 7cba2b99c..7f83795eb 100644 --- a/nag/lib/Api.php +++ b/nag/lib/Api.php @@ -1370,15 +1370,13 @@ class Nag_Api extends Horde_Registry_Api */ public function listAlarms($time, $user = null) { - require_once 'Horde/Group.php'; - if ((empty($user) || $user != Horde_Auth::getAuth()) && !$GLOBALS['registry']->isAdmin()) { return PEAR::raiseError(_("Permission Denied")); } $storage = Nag_Driver::singleton(); - $group = Group::singleton(); + $group = Horde_Group::singleton(); $alarm_list = array(); $tasklists = is_null($user) ? array_keys($GLOBALS['nag_shares']->listAllShares()) : $GLOBALS['display_tasklists']; diff --git a/nag/lib/Forms/task.php b/nag/lib/Forms/task.php index 7acbcb47b..d9e998a2e 100644 --- a/nag/lib/Forms/task.php +++ b/nag/lib/Forms/task.php @@ -53,8 +53,7 @@ class Nag_TaskForm extends Horde_Form { $users = $share->listUsers(Horde_Perms::READ); $groups = $share->listGroups(Horde_Perms::READ); if (count($groups)) { - require_once 'Horde/Group.php'; - $horde_group = Group::singleton(); + $horde_group = Horde_Group::singleton(); foreach ($groups as $group) { $users = array_merge($users, $horde_group->listAllUsers($group)); diff --git a/nag/lib/Nag.php b/nag/lib/Nag.php index 51899b107..caffe3ccb 100644 --- a/nag/lib/Nag.php +++ b/nag/lib/Nag.php @@ -835,9 +835,7 @@ class Nag throw new Nag_Exception($e); } - require_once 'Horde/Group.php'; - - $groups = Group::singleton(); + $groups = Horde_Group::singleton(); $recipients = array(); $identity = $GLOBALS['injector']->getInstance('Horde_Prefs_Identity')->getIdentity(); $from = $identity->getDefaultFromAddress(true); @@ -853,15 +851,14 @@ class Nag } } foreach ($share->listGroups(Horde_Perms::READ) as $group) { - $group = $groups->getGroupById($group); - if (is_a($group, 'PEAR_Error')) { - continue; - } - $group_users = $group->listAllUsers(); - if (is_a($group_users, 'PEAR_Error')) { - Horde::logMessage($group_users, 'ERR'); + try { + $group = $groups->getGroupById($group); + $group_users = $group->listAllUsers(); + } catch (Horde_Group_Exception $e) { + Horde::logMessage($e, 'ERR'); continue; } + foreach ($group_users as $user) { if (empty($recipients[$user])) { $recipients[$user] = Nag::_notificationPref($user, 'read', $task->tasklist); diff --git a/turba/config/sources.php.dist b/turba/config/sources.php.dist index 4d770a094..e9886c50c 100644 --- a/turba/config/sources.php.dist +++ b/turba/config/sources.php.dist @@ -701,7 +701,6 @@ $cfgSources['favourites'] = array( // 'browse' => true, //); -//require_once 'Horde/Group.php'; //$_group_driver = &Group::singleton(); //$_group_list = $_group_driver->getGroupMemberships(Horde_Auth::getAuth()); //foreach ($_group_list as $_group_id => $_group_name) { diff --git a/turba/lib/Driver/Group.php b/turba/lib/Driver/Group.php index 1941eb1b1..2251b52b3 100644 --- a/turba/lib/Driver/Group.php +++ b/turba/lib/Driver/Group.php @@ -129,9 +129,7 @@ class Turba_Driver_Group extends Turba_Driver function _getAddressBook() { - require_once 'Horde/Group.php'; - - $groups = Group::singleton(); + $groups = Horde_Group::singleton(); $members = $groups->listAllUsers($this->_gid); $addressbook = array(); foreach ($members as $member) { diff --git a/whups/lib/Application.php b/whups/lib/Application.php index cb87d8f38..400a48854 100644 --- a/whups/lib/Application.php +++ b/whups/lib/Application.php @@ -57,7 +57,6 @@ class Whups_Application extends Horde_Registry_Application protected function _init() { // TODO: Remove once they can be autoloaded - require_once 'Horde/Group.php'; require_once 'Horde/Form.php'; require_once 'Horde/Form/Renderer.php'; diff --git a/whups/lib/Forms/AddComment.php b/whups/lib/Forms/AddComment.php index 76ba7c70f..a569eac73 100644 --- a/whups/lib/Forms/AddComment.php +++ b/whups/lib/Forms/AddComment.php @@ -25,7 +25,7 @@ class AddCommentForm extends Horde_Form { /* Group restrictions. */ if ($GLOBALS['registry']->isAdmin(array('permission' => 'whups:admin')) || $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission('whups:hiddenComments', Horde_Auth::getAuth(), Horde_Perms::EDIT)) { - $groups = &Group::singleton(); + $groups = Horde_Group::singleton(); $mygroups = $groups->getGroupMemberships(Horde_Auth::getAuth()); if ($mygroups) { foreach (array_keys($mygroups) as $gid) { diff --git a/whups/lib/Forms/CreateTicket.php b/whups/lib/Forms/CreateTicket.php index 8f79a3b14..aa8c8775f 100644 --- a/whups/lib/Forms/CreateTicket.php +++ b/whups/lib/Forms/CreateTicket.php @@ -211,7 +211,7 @@ class CreateStep4Form extends Horde_Form { $this->addHidden('', 'deferred_attachment', 'text', false); /* Groups. */ - $groups = &Group::singleton(); + $groups = Horde_Group::singleton(); if ($conf['prefs']['assign_all_groups']) { $mygroups = $groups->listGroups(); } else { diff --git a/whups/lib/Forms/EditTicket.php b/whups/lib/Forms/EditTicket.php index 65860dfea..040225e5c 100644 --- a/whups/lib/Forms/EditTicket.php +++ b/whups/lib/Forms/EditTicket.php @@ -95,7 +95,7 @@ class EditTicketForm extends Horde_Form { case 'owner': if (Whups::hasPermission($vars->get('queue'), 'queue', 'assign')) { - $groups = &Group::singleton(); + $groups = Horde_Group::singleton(); if ($GLOBALS['conf']['prefs']['assign_all_groups']) { $mygroups = $groups->listGroups(); } else { @@ -172,7 +172,7 @@ class EditTicketForm extends Horde_Form { } /* Comment permissions. */ - $groups = &Group::singleton(); + $groups = Horde_Group::singleton(); $mygroups = $groups->getGroupMemberships(Horde_Auth::getAuth()); if ($mygroups) { foreach (array_keys($mygroups) as $gid) { diff --git a/whups/lib/Forms/Query.php b/whups/lib/Forms/Query.php index cf5ab9a9b..cc88c4762 100644 --- a/whups/lib/Forms/Query.php +++ b/whups/lib/Forms/Query.php @@ -89,9 +89,14 @@ class GroupCriterionForm extends Horde_Form { $this->addHidden('', 'edit', 'boolean', false); - $groups = &Group::singleton(); - $grouplist = $groups->listGroups(); - if (is_a($grouplist, 'PEAR_Error') || !count($grouplist)) { + try { + $groups = Horde_Group::singleton(); + $grouplist = $groups->listGroups(); + } catch (Horde_Group_Exception $e) { + $grouplist = array(); + } + + if (count($grouplist)) { $type_params = array(_("Could not find any groups.")); $this->addVariable(_("Groups"), 'groups', 'invalid', false, false, null, $type_params); } else { diff --git a/whups/lib/Whups.php b/whups/lib/Whups.php index 0f5aa8907..81a61720e 100644 --- a/whups/lib/Whups.php +++ b/whups/lib/Whups.php @@ -503,7 +503,7 @@ class Whups { function getOwnerCriteria($user) { $criteria = array('user:' . $user); - $groups = &Group::singleton(); + $groups = Horde_Group::singleton(); $mygroups = $groups->getGroupMemberships(Horde_Auth::getAuth()); foreach ($mygroups as $id => $group) { $criteria[] = 'group:' . $id; @@ -578,15 +578,16 @@ class Whups { $results[$user]['email'] = $identity->getValue('from_addr'); } } elseif ($type == 'group') { - $groups = &Group::singleton(); - $group = $groups->getGroupById($user); - if (is_a($group, 'PEAR_Error')) { - $results['user']['name'] = ''; - $results['user']['email'] = ''; - } else { + try { + $groups = Horde_Group::singleton(); + $group = $groups->getGroupById($user); + $results[$user]['user'] = $group->getShortName(); $results[$user]['name'] = $group->getShortName(); $results[$user]['email'] = $group->get('email'); + } catch (Horde_Group_Exception $e) { + $results['user']['name'] = ''; + $results['user']['email'] = ''; } } } diff --git a/whups/ticket/queue.php b/whups/ticket/queue.php index ceaf835af..a2a9ff92b 100644 --- a/whups/ticket/queue.php +++ b/whups/ticket/queue.php @@ -34,7 +34,7 @@ class SetQueueStep1Form extends Horde_Form { if ($GLOBALS['registry']->isAdmin(array('permission' => 'whups:admin', 'permlevel' => Horde_Perms::EDIT)) || $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission('whups:hiddenComments', Horde_Auth::getAuth(), Horde_Perms::EDIT)) { - $groups = &Group::singleton(); + $groups = Horde_Group::singleton(); $mygroups = $groups->getGroupMemberships(Horde_Auth::getAuth()); if ($mygroups) { foreach (array_keys($mygroups) as $gid) { diff --git a/whups/ticket/type.php b/whups/ticket/type.php index 51d845be1..7c83ab235 100644 --- a/whups/ticket/type.php +++ b/whups/ticket/type.php @@ -28,7 +28,7 @@ class SetTypeStep1Form extends Horde_Form { $this->addVariable(_("Comment"), 'newcomment', 'longtext', false); /* Group restrictions. */ - $groups = &Group::singleton(); + $groups = Horde_Group::singleton(); $mygroups = $groups->getGroupMemberships(Horde_Auth::getAuth()); if ($mygroups) { foreach (array_keys($mygroups) as $gid) {