mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +01:00
* Admin: allow to show groups by container: e.g. LDAP DN or arbitrary part of name found by a regular expression
This commit is contained in:
parent
975a22bee1
commit
6432807096
@ -77,19 +77,7 @@ class admin_ui
|
||||
);
|
||||
|
||||
$sel_options['tree'] = $this->tree_data();
|
||||
$sel_options['filter'] = array('' => lang('All groups'));
|
||||
foreach(self::$accounts->search(array(
|
||||
'type' => 'groups',
|
||||
'start' => false,
|
||||
'order' => 'account_lid',
|
||||
'sort' => 'ASC',
|
||||
)) as $data)
|
||||
{
|
||||
$sel_options['filter'][$data['account_id']] = empty($data['account_description']) ? $data['account_lid'] : array(
|
||||
'label' => $data['account_lid'],
|
||||
'title' => $data['account_description'],
|
||||
);
|
||||
}
|
||||
$sel_options['filter'] = array_merge([['value' => '', 'label' => lang('All groups')]], Etemplate\Widget\Select::groups());
|
||||
|
||||
$sel_options['filter2'] = array(
|
||||
'' => 'All',
|
||||
@ -103,7 +91,7 @@ class admin_ui
|
||||
$tpl->setElementAttribute('tree', 'actions', self::tree_actions());
|
||||
|
||||
// switching between iframe and nm/accounts-list depending on load parameter
|
||||
// important for first time load eg. from an other application calling it's site configuration
|
||||
// important for first time load e.g. from another application calling it's site configuration
|
||||
$tpl->setElementAttribute('iframe', 'disabled', empty($_GET['load']));
|
||||
$content['iframe'] = 'about:blank'; // we show accounts-list be default now
|
||||
if (!empty($_GET['load']))
|
||||
@ -633,73 +621,19 @@ class admin_ui
|
||||
if (!empty($data['tooltip'])) $data['tooltip'] = lang($data['tooltip']);
|
||||
// make sure keys are unique, as we overwrite tree entries otherwise
|
||||
if (isset($parent[$data[Tree::ID]])) $data[Tree::ID] .= md5($data['link']);
|
||||
$parent[$data[Tree::ID]] = self::fix_userdata($data);
|
||||
$parent[$data[Tree::ID]] = Tree::fixUserdata($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($root == '/groups')
|
||||
{
|
||||
foreach($GLOBALS['egw']->accounts->search(array(
|
||||
'type' => 'groups',
|
||||
'order' => 'account_lid',
|
||||
'sort' => 'ASC',
|
||||
)) as $group)
|
||||
{
|
||||
$tree[Tree::CHILDREN][] = self::fix_userdata(array(
|
||||
Tree::LABEL => $group['account_lid'],
|
||||
Tree::TOOLTIP => $group['account_description'],
|
||||
Tree::ID => $root.'/'.$group['account_id'],
|
||||
));
|
||||
}
|
||||
$tree[Tree::CHILDREN] = Tree::groups($root);
|
||||
}
|
||||
self::strip_item_keys($tree[Tree::CHILDREN]);
|
||||
Tree::stripChildrenKeys($tree[Tree::CHILDREN]);
|
||||
//_debug_array($tree); exit;
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix userdata as understood by tree
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
private static function fix_userdata(array $data)
|
||||
{
|
||||
if(!$data[Tree::LABEL])
|
||||
{
|
||||
$data[Tree::LABEL] = $data['text'];
|
||||
}
|
||||
// store link as userdata, maybe we should store everything not directly understood by tree this way ...
|
||||
foreach(array_diff_key($data, array_flip(array(
|
||||
Tree::ID,Tree::LABEL,Tree::TOOLTIP,'im0','im1','im2','item','child','select','open','call',
|
||||
))) as $name => $content)
|
||||
{
|
||||
$data['userdata'][] = array(
|
||||
'name' => $name,
|
||||
'content' => $content,
|
||||
);
|
||||
unset($data[$name]);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute 'item' has to be an array
|
||||
*
|
||||
* @param array $items
|
||||
*/
|
||||
private static function strip_item_keys(array &$items)
|
||||
{
|
||||
$items = array_values($items);
|
||||
foreach($items as &$item)
|
||||
{
|
||||
if (is_array($item) && isset($item['item']))
|
||||
{
|
||||
self::strip_item_keys($item['item']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static $hook_data = array();
|
||||
/**
|
||||
* Return data from regular admin hook calling display_section() instead of returning it
|
||||
|
@ -94,8 +94,8 @@ add new application admin de Neue Anwendung hinzufügen
|
||||
add new email address: admin de Neue E-Mail-Adresse hinzufügen:
|
||||
add peer server admin de Server zu Serververbund hinzufügen
|
||||
add profile admin de Profil hinzufügen
|
||||
add to group admin de Zu Gruppe hinzufügen
|
||||
add sub-category admin de Unterkategorie hinzufügen
|
||||
add to group admin de Zu Gruppe hinzufügen
|
||||
add user admin de Neuen Benutzer erstellen
|
||||
add user or group admin de Benutzer oder Gruppen eingeben
|
||||
added admin de Hinzugefügt
|
||||
@ -190,6 +190,7 @@ calendar recurrence horizont in days (default 1000) admin de Kalender Wiederholu
|
||||
can be used by application admin de Kann von folgender Anwendung verwendet werden
|
||||
can be used by group admin de Kann von folgender Gruppe verwendet werden
|
||||
can be used by user admin de Kann von folgendem Benutzer verwendet werden
|
||||
can be used to show groups by container, if enabled admin de Kann benutzt werden um Gruppen in Containern anzuzeigen, wenn eingeschaltet
|
||||
can change password admin de Darf Passwort ändern
|
||||
can not change users into groups, same sign required! admin de Das Ändern von Benutzern in Gruppen ist nicht möglich. Gleiches Kennzeichen wird benötigt!
|
||||
cancel changes admin de Änderungen abbrechen
|
||||
@ -237,6 +238,7 @@ configuration admin de Konfiguration
|
||||
configuration saved. admin de Die Konfiguration wurde erfolgreich gespeichert.
|
||||
connection dropped by imap server. admin de Verbindung von IMAP-Server beendet.
|
||||
connection is not secure! everyone can read eg. your credentials. admin de Die Verbindung ist NICHT sicher! Jeder kann z. B. Ihr Passwort lesen.
|
||||
container admin de Container
|
||||
continue admin de Weiter
|
||||
cookie domain (default empty means use full domain name, for sitemgr eg. ".domain.com" allows to use the same cookie for egw.domain.com and www.domain.com) admin de Cookie Domain<br>(Vorgabe 'leer' bedeutet den kompletten Domainnamen, für SiteMgr erlaubt z.B. ".domain.com" das gleiche Cookie für egw.domain.com und www.domain.com zu verwenden).
|
||||
cookie path (allows multiple egw sessions with different directories, has problemes with sitemgr!) admin de Cookie Pfad. Ermöglicht mehrere EGroupware-Sitzungen mit unterschiedlichen Verzeichnissen..
|
||||
@ -404,10 +406,10 @@ enter a passphrase if you would like to protect your private key by password. ad
|
||||
enter some random text for app_session <br>encryption (requires mcrypt) admin de Zufälligen Text für app_session<br>Verschlüsselung (benötigt mcrypt)
|
||||
enter the background color for the login page admin de Hintergrundfarbe für die Anmeldeseite
|
||||
enter the background color for the site title admin de Hintergrundfarbe für den Titel der Installation
|
||||
enter the full path for temporary files.<br>examples: /tmp, c:\temp admin de Vollständiger Pfad für temporäre Dateien.<br>Beispiel: /tmp, C:\TEMP
|
||||
enter the full path for temporary files.<br>examples: /tmp, c:temp admin de Vollständiger Pfad für temporäre Dateien.<br>Beispiel: /tmp, C:\TEMP
|
||||
enter the full path for users and group files.<br>examples: /files, e:\files admin de Vollständiger Pfad für Benutzer- und Gruppen-Dateien.<br>Beispiel: /files, E:\Files
|
||||
enter the full path for temporary files.<br>examples: /tmp, c:\temp admin de Vollständiger Pfad für temporäre Dateien.<br>Beispiel: /tmp, C:\TEMP
|
||||
enter the full path for users and group files.<br>examples: /files, e:files admin de Vollständiger Pfad für Benutzer- und Gruppen-Dateien.<br>Beispiel: /files, E:\Files
|
||||
enter the full path for users and group files.<br>examples: /files, e:\files admin de Vollständiger Pfad für Benutzer- und Gruppen-Dateien.<br>Beispiel: /files, E:\Files
|
||||
enter the hostname of the machine on which this server is running admin de Hostname des Computers auf dem der Server läuft
|
||||
enter the location of egroupware's url.<br>example: http://www.domain.com/egroupware or /egroupware<br><b>no trailing slash</b> admin de URL zur EGroupware-Installation.<br>Beispiel: https://egw.domain.com/egroupware or /egroupware<br><b>keinen nachfolgenden Slash /</b>
|
||||
enter the search string. to show all entries, empty this field and press the submit button again admin de Geben Sie Ihren Suchbegriff ein. Um alle Einträge anzuzeigen geben Sie keinen Begriff ein und drücken Sie den Suchen-Knopf noch einmal
|
||||
@ -498,6 +500,7 @@ group excepted from above export limit (admins are always excepted) admin de Gru
|
||||
group has been added common de Gruppe wurde hinzugefügt.
|
||||
group has been deleted common de Gruppe wurde gelöscht.
|
||||
group has been updated common de Gruppe wurde aktualisiert.
|
||||
group hierarchy admin de Gruppen Hierarchie
|
||||
group list admin de Liste der Gruppen
|
||||
group manager admin de Gruppenmanager
|
||||
group name admin de Gruppenname
|
||||
@ -754,6 +757,7 @@ quota size in mbyte admin de Quota-Größe in MByte
|
||||
re-enter password admin de Passwort wiederholen
|
||||
read this list of methods. admin de Diese Liste der Methoden lesen.
|
||||
register application hooks admin de Registrieren der "Hooks" der Anwendungen
|
||||
regular expression to find part to use as container admin de Regulärer Ausdruck um den Teil zu finden, der als Container verwendet wird
|
||||
reject passwords containing part of username or full name (3 or more characters long) admin de Passwörter zurückweisen die einen Teil des Benutzernamen oder vollständigen Namens beinhalten (3 oder mehr Zeichen lang)
|
||||
relay access checked admin de Nicht angemeldetes Senden überprüft
|
||||
remark admin de Bemerkung
|
||||
@ -833,6 +837,7 @@ show as optional, but required once user has it setup admin de Als optional anze
|
||||
show as required, but only once user has it setup admin de Als benötigt anzeigen, aber nur benötigt, wenn Benutzer sie eingerichtet hat
|
||||
show current action admin de Aktuelle Aktion anzeigen
|
||||
show error log admin de Fehlerprotokoll anzeigen
|
||||
show groups in container based on admin de Zeige Gruppen in Container basierend auf
|
||||
show members admin de Mitglieder dieser Gruppe anzeigen
|
||||
show phpinfo() admin de phpinfo() anzeigen
|
||||
show session ip address admin de IP-Adresse der Sitzung anzeigen
|
||||
|
@ -190,6 +190,7 @@ calendar recurrence horizont in days (default 1000) admin en Calendar recurrence
|
||||
can be used by application admin en Can be used by application
|
||||
can be used by group admin en Can be used by group
|
||||
can be used by user admin en Can be used by user
|
||||
can be used to show groups by container, if enabled admin en Can be used to show groups by container, if enabled
|
||||
can change password admin en Can change password
|
||||
can not change users into groups, same sign required! admin en Can NOT change users into groups, same sign required!
|
||||
cancel changes admin en Cancel changes
|
||||
@ -237,6 +238,7 @@ configuration admin en Configuration
|
||||
configuration saved. admin en Configuration saved.
|
||||
connection dropped by imap server. admin en Connection dropped by IMAP server.
|
||||
connection is not secure! everyone can read eg. your credentials. admin en Connection is NOT secure! Everyone can read eg. your credentials.
|
||||
container admin en Container
|
||||
continue admin en Continue
|
||||
cookie domain (default empty means use full domain name, for sitemgr eg. ".domain.com" allows to use the same cookie for egw.domain.com and www.domain.com) admin en Cookie domain. Default empty uses full domain name. E.g. in Site Manager ".domain.com" allows to use the same cookie for egw.domain.com and www.domain.com.
|
||||
cookie path (allows multiple egw sessions with different directories, has problemes with sitemgr!) admin en Cookie path. Allows multiple EGroupware sessions with different directories.
|
||||
@ -404,10 +406,10 @@ enter a passphrase if you would like to protect your private key by password. ad
|
||||
enter some random text for app_session <br>encryption (requires mcrypt) admin en Enter some random text for app_session <br>encryption, requires mcrypt
|
||||
enter the background color for the login page admin en Enter the background colour for the login page
|
||||
enter the background color for the site title admin en Enter the background colour for the site title
|
||||
enter the full path for temporary files.<br>examples: /tmp, c:\temp admin en Enter the full path for temporary files.<br>Examples: /tmp, C:\TEMP
|
||||
enter the full path for temporary files.<br>examples: /tmp, c:temp admin en Enter the full path for temporary files.<br>Examples: /tmp, C:\TEMP
|
||||
enter the full path for users and group files.<br>examples: /files, e:\files admin en Enter the full path for users and group files.<br>Examples: /files, E:\FILES
|
||||
enter the full path for temporary files.<br>examples: /tmp, c:\temp admin en Enter the full path for temporary files.<br>Examples: /tmp, C:\TEMP
|
||||
enter the full path for users and group files.<br>examples: /files, e:files admin en Enter the full path for users and group files.<br>Examples: /files, E:\FILES
|
||||
enter the full path for users and group files.<br>examples: /files, e:\files admin en Enter the full path for users and group files.<br>Examples: /files, E:\FILES
|
||||
enter the hostname of the machine on which this server is running admin en Enter the host name of the machine on which this server is running
|
||||
enter the location of egroupware's url.<br>example: http://www.domain.com/egroupware or /egroupware<br><b>no trailing slash</b> admin en Enter the location of EGroupware's URL.<br>Example: https://egw.domain.com/egroupware or /egroupware<br><b>No trailing slash</b>
|
||||
enter the search string. to show all entries, empty this field and press the submit button again admin en Enter the search string. To show all entries, empty this field and press the SUBMIT button again
|
||||
@ -498,6 +500,7 @@ group excepted from above export limit (admins are always excepted) admin en Gro
|
||||
group has been added common en Group has been added.
|
||||
group has been deleted common en Group has been deleted.
|
||||
group has been updated common en Group has been updated.
|
||||
group hierarchy admin en Group hierarchy
|
||||
group list admin en Group list
|
||||
group manager admin en Group manager
|
||||
group name admin en Group name
|
||||
@ -754,6 +757,7 @@ quota size in mbyte admin en Quota size in MByte
|
||||
re-enter password admin en Re-enter password
|
||||
read this list of methods. admin en Read this list of methods.
|
||||
register application hooks admin en Register application hooks
|
||||
regular expression to find part to use as container admin en Regular expression to find part to use as container
|
||||
reject passwords containing part of username or full name (3 or more characters long) admin en Reject passwords containing part of username or full name (3 or more characters long)
|
||||
relay access checked admin en Relay access checked
|
||||
remark admin en Remark
|
||||
@ -833,6 +837,7 @@ show as optional, but required once user has it setup admin en Show as optional,
|
||||
show as required, but only once user has it setup admin en Show as required, but only once user has it setup
|
||||
show current action admin en Show current action
|
||||
show error log admin en Show error log
|
||||
show groups in container based on admin en Show groups in container based on
|
||||
show members admin en Show members
|
||||
show phpinfo() admin en Show phpinfo()
|
||||
show session ip address admin en Show session IP address
|
||||
|
@ -250,6 +250,9 @@ class Groups
|
||||
{
|
||||
$readonlys['button[save]'] = $readonlys['button[apply]'] = true;
|
||||
}
|
||||
// disable DN for LDAP, AD or synced groups were the real DN is stored here
|
||||
$content['disable_dn'] = $GLOBALS['egw_info']['server']['account_repository'] !== 'sql' ||
|
||||
!empty($GLOBALS['egw_info']['server']['account_import_source']) && $GLOBALS['egw_info']['server']['account_import_type'] !== 'users';
|
||||
|
||||
$tpl->exec('admin.'.self::class.'.edit', $content, $sel_options, $readonlys, $content, 2);
|
||||
}
|
||||
|
@ -53,14 +53,26 @@
|
||||
<option value="disabled">{No}</option>
|
||||
</et2-select>
|
||||
</row>
|
||||
<!-- remove currently not supported/necessary development option debug_minify
|
||||
<row>
|
||||
<et2-description value="Disable minifying of javascript and CSS files" label="%s:"></et2-description>
|
||||
<et2-select id="newsettings[debug_minify]">
|
||||
<et2-description value="Group hierarchy" span="all" class="subHeader"></et2-description>
|
||||
</row>
|
||||
<row>
|
||||
<et2-description value="Show groups in container based on" label="%s:"></et2-description>
|
||||
<et2-select id="newsettings[group_container_attribute]">
|
||||
<option value="">{No} - {Default}</option>
|
||||
<option value="True">Yes</option>
|
||||
<option value="account_lid">{Group name}: /^([^ ]+) / --> $1</option>
|
||||
<option value="account_dn">LDAP DN: /,CN=([^,]+),/ --> $1</option>
|
||||
</et2-select>
|
||||
</row -->
|
||||
</row>
|
||||
<row>
|
||||
<et2-description value="Regular expression to find part to use as container" label="%s:"></et2-description>
|
||||
<et2-hbox>
|
||||
<et2-textbox id="newsettings[group_container_regexp]" placeholder="/,CN=([^,]+),/"></et2-textbox>
|
||||
<et2-description value="-->" style="position: relative; top: .5em"></et2-description>
|
||||
<et2-textbox id="newsettings[group_container_replace]" placeholder="$1" width="100px"></et2-textbox>
|
||||
</et2-hbox>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<et2-description value="Encryption" span="all" class="subHeader"></et2-description>
|
||||
</row>
|
||||
@ -390,7 +402,7 @@
|
||||
</grid>
|
||||
</template>
|
||||
<template id="admin.config" template="" lang="" group="0" version="18.1">
|
||||
<et2-tabbox id="tabs" width="100%">
|
||||
<et2-tabbox id="tabs" width="100%" tabHeight="700">
|
||||
<tabs>
|
||||
<tab id="general" label="General"/>
|
||||
<tab id="appearance" label="Appearance"/>
|
||||
|
@ -43,6 +43,10 @@
|
||||
<et2-description value="Filesystem quota"></et2-description>
|
||||
<et2-textbox id="quota" disabled="!@epl" placeholder="@default_quota"></et2-textbox>
|
||||
</row>
|
||||
<row>
|
||||
<et2-description value="Container" for="account_dn"></et2-description>
|
||||
<et2-textbox id="account_dn" maxlength="255" disabled="@disable_dn" statustext="Can be used to show groups by container, if enabled"></et2-textbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<et2-tabbox id="tabs" class="et2_nowrap" span="all" width="100%" tabHeight="250px">
|
||||
|
@ -14,7 +14,7 @@
|
||||
<template template="@template" width="99%"/>
|
||||
</row>
|
||||
<row disabled="!@need_tab">
|
||||
<et2-tabbox id="tabs2" width="100%">
|
||||
<et2-tabbox id="tabs2" width="100%" tabHeight="700">
|
||||
<tabs>
|
||||
<tab id="config" label="Configuration"/>
|
||||
</tabs>
|
||||
|
@ -565,7 +565,7 @@ class Sql
|
||||
foreach($this->contacts->search($criteria,
|
||||
array_merge(array(1,'n_given','n_family','id','created','modified','files',$this->table.'.account_id AS account_id'),$email_cols),
|
||||
$order, "account_lid,account_type,account_status,account_expires,account_primary_group,account_description".
|
||||
",account_lastlogin,account_lastloginfrom,account_lastpwd_change",
|
||||
",account_lastlogin,account_lastloginfrom,account_lastpwd_change,account_uuid,account_dn",
|
||||
$wildcard,false,$query[0] == '!' ? 'AND' : 'OR',
|
||||
!empty($param['offset']) ? array($param['start'], $param['offset']) : $param['start'] ?? false,
|
||||
$filter,$join) ?? [] as $contact)
|
||||
@ -575,6 +575,8 @@ class Sql
|
||||
$account_id = ($contact['account_type'] == 'g' ? -1 : 1) * $contact['account_id'];
|
||||
$accounts[$account_id] = array(
|
||||
'account_id' => $account_id,
|
||||
'account_dn' => $contact['account_dn'],
|
||||
'account_uuid' => $contact['account_uuid'],
|
||||
'account_lid' => $contact['account_lid'],
|
||||
'account_type' => $contact['account_type'],
|
||||
'account_firstname' => $contact['n_given'],
|
||||
|
@ -1128,7 +1128,7 @@ class Widget
|
||||
/**
|
||||
* disables all cells with name == $name
|
||||
*
|
||||
* @param sting $name cell-name
|
||||
* @param string $name cell-name
|
||||
* @param boolean $disabled =true disable or enable a cell, default true=disable
|
||||
* @return reference to attribute
|
||||
*/
|
||||
|
@ -448,9 +448,9 @@ class Select extends Etemplate\Widget
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix already html-encoded options, eg. "&nbps" AND optinal re-index array to keep order
|
||||
* Fix already html-encoded options, e.g. "&nbps;" AND optional re-index array to keep order
|
||||
*
|
||||
* Get run automatic for everything in $sel_options by etemplate_new::exec / etemplate_new::fix_sel_options
|
||||
* Get run automatic for everything in $sel_options by Api\Etemplate::exec / Api\Etemplate::fix_sel_options
|
||||
*
|
||||
* @param array $options
|
||||
* @param boolean $use_array_of_objects Re-indexes options, making everything more complicated
|
||||
@ -1104,6 +1104,44 @@ class Select extends Etemplate\Widget
|
||||
$response = Api\Json\Response::get();
|
||||
$response->data($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups including container, if enabled
|
||||
*
|
||||
* Internally using Tree::groups() to not implement container logic again.
|
||||
*
|
||||
* @param array|null $tree
|
||||
* @param string $prefix to use container as prefix instead of not working opt-groups
|
||||
* @return array[]
|
||||
* @todo fix options here or select-widget to understand and show opt-groups, incl. icons
|
||||
*/
|
||||
public static function groups(?array $tree=null, $prefix='')
|
||||
{
|
||||
if (!isset($tree)) $tree = Tree::groups('');
|
||||
$options = [];
|
||||
foreach($tree as $group)
|
||||
{
|
||||
if (isset($group[Tree::CHILDREN]))
|
||||
{
|
||||
$options[/*$group[Tree::LABEL]*/] = [
|
||||
'value' => $group[Tree::LABEL],
|
||||
'label' => self::groups($group[Tree::CHILDREN], $group[Tree::LABEL]),
|
||||
'title' => $group[Tree::TOOLTIP] ?? null,
|
||||
'icon' => $group[Tree::IMAGE_FOLDER_CLOSED],
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
$options[/*$group[Tree::ID]*/] = [
|
||||
'value' => $group[Tree::ID],
|
||||
'label' => ($prefix ? $prefix.': ' : '').$group[Tree::LABEL],
|
||||
'title' => $group[Tree::TOOLTIP],
|
||||
'icon' => $group[Tree::IMAGE_LEAF],
|
||||
];
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
Etemplate\Widget::registerWidget(__NAMESPACE__ . '\\Select', array('et2-select', 'selectbox', 'listbox', 'select',
|
||||
|
@ -20,28 +20,28 @@ use EGroupware\Api;
|
||||
*
|
||||
* Example initialisation of tree via $sel_options array:
|
||||
*
|
||||
* use Api\Etemplate\Widget\Tree as tree;
|
||||
* use Api\Etemplate\Widget\Tree;
|
||||
*
|
||||
* $sel_options['tree'] = array(
|
||||
* tree::ID => 0, tree::CHILDREN => array( // ID of root has to be 0!
|
||||
* Tree::ID => 0, Tree::CHILDREN => array( // ID of root has to be 0!
|
||||
* array(
|
||||
* tree::ID => '/INBOX',
|
||||
* tree::LABEL => 'INBOX', tree::TOOLTIP => 'Your inbox',
|
||||
* tree::OPEN => 1, tree::IMAGE_FOLDER_OPEN => 'kfm_home.png', tree::IMAGE_FOLDER_CLOSED => 'kfm_home.png',
|
||||
* tree::CHILDREN => array(
|
||||
* array(tree::ID => '/INBOX/sub', tree::LABEL => 'sub', tree::IMAGE_LEAF => 'folderClosed.gif'),
|
||||
* array(tree::ID => '/INBOX/sub2', tree::LABEL => 'sub2', tree::IMAGE_LEAF => 'folderClosed.gif'),
|
||||
* Tree::ID => '/INBOX',
|
||||
* Tree::LABEL => 'INBOX', Tree::TOOLTIP => 'Your inbox',
|
||||
* Tree::OPEN => 1, Tree::IMAGE_FOLDER_OPEN => 'kfm_home.png', Tree::IMAGE_FOLDER_CLOSED => 'kfm_home.png',
|
||||
* Tree::CHILDREN => array(
|
||||
* array(Tree::ID => '/INBOX/sub', Tree::LABEL => 'sub', Tree::IMAGE_LEAF => 'folderClosed.gif'),
|
||||
* array(Tree::ID => '/INBOX/sub2', Tree::LABEL => 'sub2', Tree::IMAGE_LEAF => 'folderClosed.gif'),
|
||||
* ),
|
||||
* tree::CHECKED => true,
|
||||
* Tree::CHECKED => true,
|
||||
* ),
|
||||
* array(
|
||||
* tree::ID => '/user',
|
||||
* tree::LABEL => 'user',
|
||||
* tree::CHILDREN => array(
|
||||
* array(tree::ID => '/user/birgit', tree::LABEL => 'birgit', tree::IMAGE_LEAF => 'folderClosed.gif'),
|
||||
* array(tree::ID => '/user/ralf', tree::LABEL => 'ralf', tree::AUTOLOAD_CHILDREN => 1),
|
||||
* Tree::ID => '/user',
|
||||
* Tree::LABEL => 'user',
|
||||
* Tree::CHILDREN => array(
|
||||
* array(Tree::ID => '/user/birgit', Tree::LABEL => 'birgit', Tree::IMAGE_LEAF => 'folderClosed.gif'),
|
||||
* array(Tree::ID => '/user/ralf', Tree::LABEL => 'ralf', Tree::AUTOLOAD_CHILDREN => 1),
|
||||
* ),
|
||||
* tree::NOCHECKBOX => true
|
||||
* Tree::NOCHECKBOX => true
|
||||
* ),
|
||||
* ));
|
||||
*
|
||||
@ -550,4 +550,113 @@ class Tree extends Etemplate\Widget
|
||||
}
|
||||
return $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix userdata as understood by tree
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public static function fixUserdata(array $data)
|
||||
{
|
||||
// store link as userdata, maybe we should store everything not directly understood by tree this way ...
|
||||
foreach(array_diff_key($data, array_flip([
|
||||
self::ID, self::LABEL, self::TOOLTIP, self::IMAGE_LEAF, self::IMAGE_FOLDER_OPEN, self::IMAGE_FOLDER_CLOSED,
|
||||
'item', self::AUTOLOAD_CHILDREN, 'select', self::OPEN, 'call',
|
||||
])) as $name => $content)
|
||||
{
|
||||
$data['userdata'][] = array(
|
||||
'name' => $name,
|
||||
'content' => $content,
|
||||
);
|
||||
unset($data[$name]);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get list of all groups as tree, taking container into account, if enabled
|
||||
*
|
||||
* @param string $root root for building tree-IDs, "" for just using IDs, no path
|
||||
* @return array[] with tree-children, groups have IDs $root/$account_id (independent of container!), while container use $root/md5($container_name)
|
||||
*/
|
||||
public static function groups(string $root='/groups')
|
||||
{
|
||||
if ($root) $root = rtrim($root, '/').'/';
|
||||
$group_container_attr = $GLOBALS['egw_info']['server']['group_container_attribute'] ?? '';
|
||||
static $default_regexp = [
|
||||
'account_lid' => '/^([^ ]+) /',
|
||||
'account_dn' => '/,CN=([^,]+),/i',
|
||||
];
|
||||
$group_container_regexp = $GLOBALS['egw_info']['server']['group_container_regexp'] ?? $default_regexp[$group_container_attr] ?? null;
|
||||
$group_container_replace = $GLOBALS['egw_info']['server']['group_container_replace'] ?? '$1';
|
||||
|
||||
$children = [];
|
||||
foreach(Api\Accounts::getInstance()->search(array(
|
||||
'type' => 'groups',
|
||||
'order' => 'account_lid',
|
||||
'sort' => 'ASC',
|
||||
'start' => false, // to NOT limit number of returned groups
|
||||
)) as $group)
|
||||
{
|
||||
if ($group_container_attr && !empty($group[$group_container_attr]) &&
|
||||
preg_match($group_container_regexp, $group[$group_container_attr], $matches) &&
|
||||
($container_name = ucfirst($matches[substr($group_container_replace, 1)] ?? '')))
|
||||
{
|
||||
foreach($children as &$container)
|
||||
{
|
||||
if ($container[Tree::LABEL] === $container_name) break;
|
||||
}
|
||||
if ($container[Tree::LABEL] !== $container_name)
|
||||
{
|
||||
$children[] = self::fixUserdata([
|
||||
Tree::LABEL => $container_name,
|
||||
Tree::ID => $root.md5($container_name),
|
||||
Tree::IMAGE_FOLDER_OPEN => Api\Image::find('api', 'dhtmlxtree/folderOpen'),
|
||||
Tree::IMAGE_FOLDER_CLOSED => Api\Image::find('api', 'dhtmlxtree/folderClosed'),
|
||||
Tree::CHILDREN => [],
|
||||
]);
|
||||
$container =& $children[count($children)-1];
|
||||
}
|
||||
$container[Tree::CHILDREN][] = self::fixUserdata([
|
||||
Tree::LABEL => $group['account_lid'],
|
||||
Tree::TOOLTIP => $group['account_description'],
|
||||
Tree::ID => $root.$group['account_id'],
|
||||
Tree::IMAGE_LEAF => Api\Image::find('addressbook', 'group'),
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$children[] = self::fixUserdata([
|
||||
Tree::LABEL => $group['account_lid'],
|
||||
Tree::TOOLTIP => $group['account_description'],
|
||||
Tree::ID => $root.$group['account_id'],
|
||||
Tree::IMAGE_LEAF => Api\Image::find('addressbook', 'group'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
// we need to sort (again), otherwise the containers would not be alphabetic sorted (Groups are already)
|
||||
uasort($children, static function ($a, $b) {
|
||||
return strnatcasecmp($a[Tree::LABEL], $b[Tree::LABEL]);
|
||||
});
|
||||
return $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute Tree::Children='item' has to be an array (keys: 0, 1, ...), not object/associate array
|
||||
*
|
||||
* @param array $items
|
||||
*/
|
||||
public static function stripChildrenKeys(array &$items)
|
||||
{
|
||||
$items = array_values($items);
|
||||
foreach($items as &$item)
|
||||
{
|
||||
if (is_array($item) && isset($item[self::CHILDREN]))
|
||||
{
|
||||
self::stripChildrenKeys($item[self::CHILDREN]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user