Replace other user folders uids with display name (Bifrost#T216238)

Extends existing functionality that worked in kolab plugins' UI
in a way that:
- ldap lookups are optionally cached
- replacing is done also in Mail/Settings parts of the UI
- object_prettyname() uses the same technique as folders listings
This commit is contained in:
Aleksander Machniak 2019-06-13 13:33:35 +00:00
parent 9da21b887c
commit acd1740a29
4 changed files with 177 additions and 48 deletions

View file

@ -72,6 +72,11 @@ class kolab_folders extends rcube_plugin
// ACL plugin hooks
$this->add_hook('acl_rights_simple', array($this, 'acl_rights_simple'));
$this->add_hook('acl_rights_supported', array($this, 'acl_rights_supported'));
// Resolving other user folder names
$this->add_hook('render_mailboxlist', array($this, 'render_folderlist'));
$this->add_hook('render_folder_selector', array($this, 'render_folderlist'));
$this->add_hook('folders_list', array($this, 'render_folderlist'));
}
/**
@ -709,6 +714,7 @@ class kolab_folders extends rcube_plugin
* Static getter for default folder of the given type
*
* @param string $type Folder type
*
* @return string Folder name
*/
public static function default_folder($type)
@ -781,4 +787,74 @@ class kolab_folders extends rcube_plugin
);
}
}
/**
* Handler for various folders list widgets (hooks)
*
* @param array $args Hash array with hook parameters
*
* @return array Hash array with modified hook parameters
*/
public function render_folderlist($args)
{
$storage = $this->rc->get_storage();
$ns_other = $storage->get_namespace('other');
$is_fl = $this->rc->plugins->is_processing('folders_list');
foreach ((array) $ns_other as $root) {
$delim = $root[1];
$prefix = rtrim($root[0], $delim);
$length = strlen($prefix);
if (!$length) {
continue;
}
// folders_list hook mode
if ($is_fl) {
foreach ((array) $args['list'] as $folder_name => $folder) {
if (strpos($folder_name, $root[0]) === 0 && !substr_count($folder_name, $root[1], $length+1)) {
if ($name = $this->folder_id2username(substr($folder_name, $length+1))) {
$old = $args['list'][$folder_name]['display'];
$content = $args['list'][$folder_name]['content'];
$name = rcube::Q($name);
$content = str_replace(">$old<", ">$name<", $content);
$args['list'][$folder_name]['display'] = $name;
$args['list'][$folder_name]['content'] = $content;
}
}
}
// TODO: Re-sort the list
}
// render_* hooks mode
else if (!empty($args['list'][$prefix]) && !empty($args['list'][$prefix]['folders'])) {
$map = array();
foreach ($args['list'][$prefix]['folders'] as $folder_name => $folder) {
if ($name = $this->folder_id2username($folder_name)) {
$args['list'][$prefix]['folders'][$folder_name]['name'] = $name;
}
$map[$folder_name] = $name ?: $args['list'][$prefix]['folders'][$folder_name]['name'];
}
// Re-sort the list
uasort($map, 'strcoll');
$args['list'][$prefix]['folders'] = array_replace($map, $args['list'][$prefix]['folders']);
}
}
return $args;
}
/**
* Map other user (imap) folder identifier to user name
* @see kolab_storage::folder_id2user()
*/
private static function folder_id2username($uid)
{
return kolab_storage::folder_id2user($uid, true);
}
}

View file

@ -64,6 +64,18 @@ $config['kolab_users_id_attrib'] = null;
// Use these attributes when searching users in LDAP
$config['kolab_users_search_attrib'] = array('cn','mail','alias');
// Which property of the LDAP user record to use as a display name.
// Defaults to the 'kolab_auth_name' configuration option.
$config['kolab_users_name_field'] = null;
// Type of cache for uid-to-user map. Supported: 'db', 'apc', 'memcache' and 'memcached'.
// Note: This stores only other user folder identifier to user attributes map.
$config['kolab_users_cache'] = null;
// lifetime of shared folder mapping cache
// possible units: s, m, h, d, w
$config['kolab_users_cache_ttl'] = '10d';
// JSON-RPC endpoint configuration of the Bonnie web service providing historic data for groupware objects
$config['kolab_bonnie_api'] = array(
'uri' => 'https://<kolab-hostname>:8080/api/rpc',

View file

@ -46,12 +46,14 @@ class kolab_storage
private static $ready = false;
private static $with_tempsubs = true;
private static $subscriptions;
private static $ldapcache = array();
private static $typedata = array();
private static $states;
private static $config;
private static $imap;
private static $ldap;
// Default folder names
private static $default_folders = array(
'event' => 'Calendar',
@ -354,7 +356,6 @@ class kolab_storage
return '';
}
/**
* Deletes IMAP folder
*
@ -421,7 +422,6 @@ class kolab_storage
return false;
}
/**
* Renames IMAP folder
*
@ -457,7 +457,6 @@ class kolab_storage
return $success;
}
/**
* Rename or Create a new IMAP folder.
*
@ -552,7 +551,6 @@ class kolab_storage
return $result ? $folder : false;
}
/**
* Getter for human-readable name of Kolab object (folder)
* with kolab_custom_display_names support.
@ -637,20 +635,18 @@ class kolab_storage
if (!$found && !empty($namespace['other'])) {
foreach ($namespace['other'] as $ns) {
if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
// remove namespace prefix
// remove namespace prefix and extract username
$folder = substr($folder, strlen($ns[0]));
$delim = $ns[1];
// get username
$pos = strpos($folder, $delim);
if ($pos) {
$prefix = '('.substr($folder, 0, $pos).')';
$folder = substr($folder, $pos+1);
}
else {
$prefix = '('.$folder.')';
$folder = '';
}
// get username part and map it to user name
$pos = strpos($folder, $delim);
$fid = $pos ? substr($folder, 0, $pos) : $folder;
$fid = self::folder_id2user($fid, true);
$fid = str_replace($delim, '', $fid);
$prefix = "($fid)";
$folder = $pos ? substr($folder, $pos + 1) : '';
$found = true;
$folder_ns = 'other';
break;
@ -729,7 +725,6 @@ class kolab_storage
return $name;
}
/**
* Creates a SELECT field with folders list
*
@ -812,7 +807,6 @@ class kolab_storage
return $select;
}
/**
* Returns a list of folder names
*
@ -976,7 +970,6 @@ class kolab_storage
return $folders;
}
/**
* Sort the given list of kolab folders by namespace/name
*
@ -1006,7 +999,6 @@ class kolab_storage
return $out;
}
/**
* Check the folder tree and add the missing parents as virtual folders
*
@ -1082,7 +1074,6 @@ class kolab_storage
return $_folders;
}
/**
* Returns folder types indexed by folder name
*
@ -1149,7 +1140,6 @@ class kolab_storage
return self::$typedata[$prefix];
}
/**
* Callback for array_map to select the correct annotation value
*/
@ -1165,7 +1155,6 @@ class kolab_storage
return null;
}
/**
* Returns type of IMAP folder
*
@ -1197,7 +1186,6 @@ class kolab_storage
return 'mail';
}
/**
* Sets folder content-type.
*
@ -1220,7 +1208,6 @@ class kolab_storage
return $success;
}
/**
* Check subscription status of this folder
*
@ -1242,7 +1229,6 @@ class kolab_storage
($temp && in_array($folder, (array)$_SESSION['kolab_subscribed_folders']));
}
/**
* Change subscription status of this folder
*
@ -1273,7 +1259,6 @@ class kolab_storage
return false;
}
/**
* Change subscription status of this folder
*
@ -1301,7 +1286,6 @@ class kolab_storage
return false;
}
/**
* Check activation status of this folder
*
@ -1316,7 +1300,6 @@ class kolab_storage
return in_array($folder, $active_folders);
}
/**
* Change activation status of this folder
*
@ -1331,7 +1314,6 @@ class kolab_storage
return self::set_state($folder, true);
}
/**
* Change activation status of this folder
*
@ -1347,7 +1329,6 @@ class kolab_storage
return self::set_state($folder, false);
}
/**
* Return list of active folders
*/
@ -1379,7 +1360,6 @@ class kolab_storage
return self::$states;
}
/**
* Update list of active folders
*/
@ -1504,7 +1484,6 @@ class kolab_storage
}
}
/**
*
* @param mixed $query Search value (or array of field => value pairs)
@ -1544,7 +1523,6 @@ class kolab_storage
return $results;
}
/**
* Returns a list of IMAP folders shared by the given user
*
@ -1584,7 +1562,6 @@ class kolab_storage
return $folders;
}
/**
* Get a list of (virtual) top-level folders from the other users namespace
*
@ -1635,7 +1612,6 @@ class kolab_storage
return $folders;
}
/**
* Handler for user_delete plugin hooks
*
@ -1673,4 +1649,79 @@ class kolab_storage
return $metadata[$folder];
}
}
/**
* Get user attributes for specified other user (imap) folder identifier.
* Note: This uses LDAP config/code from kolab_auth.
*
* @param string $folder_id Folder name w/o path (imap user identifier)
* @param bool $as_string Return configured display name attribute value
*
* @return array User attributes
* @see self::ldap()
*/
public static function folder_id2user($folder_id, $as_string = false)
{
static $domain, $cache, $name_attr;
$rcube = rcube::get_instance();
if ($domain === null) {
list(, $domain) = explode('@', $rcube->get_user_name());
}
if ($name_attr === null) {
$name_attr = (array) (self::$config->get('kolab_users_name_field', self::$config->get('kolab_auth_name')) ?: 'name');
}
$token = $folder_id;
if ($domain && strpos($find, '@') === false) {
$token .= '@' . $domain;
}
if ($cache === null) {
$cache = $rcube->get_cache_shared('kolab_users') ?: false;
}
// use value cached in memory for repeated lookups
if (!$cache && array_key_exists($token, self::$ldapcache)) {
$user = self::$ldapcache[$token];
}
if (empty($user) && $cache) {
$user = $cache->get($token);
}
if (empty($user) && ($ldap = kolab_storage::ldap())) {
$user = $ldap->get_user_record($token, $_SESSION['imap_host']);
if (!empty($user)) {
$keys = array('displayname', 'name', 'mail'); // supported keys
$user = array_intersect_key($user, array_flip($keys));
if (!empty($user)) {
if ($cache) {
$cache->set($token, $user);
}
else {
self::$ldapcache[$token] = $user;
}
}
}
}
if (!empty($user)) {
if ($as_string) {
foreach ($name_attr as $attr) {
if ($name = $user[$attr]) {
return $name;
}
}
return $user['displayname'] ?: $user['name'];
}
return $user;
}
}
}

View file

@ -23,8 +23,6 @@
*/
class kolab_storage_folder_user extends kolab_storage_folder_virtual
{
protected static $ldapcache = array();
public $ldaprec;
public $type;
@ -36,21 +34,13 @@ class kolab_storage_folder_user extends kolab_storage_folder_virtual
parent::__construct($name, kolab_storage::object_prettyname($name), 'other', $parent);
if (!empty($ldaprec)) {
self::$ldapcache[$name] = $this->ldaprec = $ldaprec;
$this->ldaprec = $ldaprec;
}
// use value cached in memory for repeated lookups
else if (array_key_exists($name, self::$ldapcache)) {
$this->ldaprec = self::$ldapcache[$name];
}
// lookup user in LDAP and set $this->ldaprec
else if ($ldap = kolab_storage::ldap()) {
// get domain from current user
list(,$domain) = explode('@', rcube::get_instance()->get_user_name());
$this->ldaprec = $ldap->get_user_record(parent::get_foldername($this->name) . '@' . $domain, $_SESSION['imap_host']);
else {
$this->ldaprec = kolab_storage::folder_id2user(parent::get_foldername($this->name));
if (!empty($this->ldaprec)) {
$this->ldaprec['kolabtargetfolder'] = $name;
}
self::$ldapcache[$name] = $this->ldaprec;
}
}