diff --git a/admin/inc/class.admin_ui.inc.php b/admin/inc/class.admin_ui.inc.php
index 6c94305b50..a05dcb56d1 100644
--- a/admin/inc/class.admin_ui.inc.php
+++ b/admin/inc/class.admin_ui.inc.php
@@ -507,7 +507,9 @@ class admin_ui
{
$group['members'] = $GLOBALS['egw']->accounts->members($group['account_id'],true);
}
- $rows[] = $group;
+ $rows[] = $group+[
+ 'container' => Api\Accounts::container($group) ?? lang('None'),
+ ];
}
$rows['is_huge'] = $is_huge;
return $GLOBALS['egw']->accounts->total;
diff --git a/admin/templates/default/index.xet b/admin/templates/default/index.xet
index 45eef7a5a8..b693d76ddf 100644
--- a/admin/templates/default/index.xet
+++ b/admin/templates/default/index.xet
@@ -65,6 +65,7 @@
+
@@ -74,6 +75,7 @@
+
diff --git a/api/src/Accounts.php b/api/src/Accounts.php
index 6445cb5a31..ef6fe5fd0a 100644
--- a/api/src/Accounts.php
+++ b/api/src/Accounts.php
@@ -1592,6 +1592,43 @@ class Accounts
});
}
+ /**
+ * Get group-container attributes incl. default values
+ *
+ * @return array with values [$group_container_attribute, $group_container_regexp, $group_container_replace]
+ */
+ public static function groupContainerAttributs()
+ {
+ $group_container_attribute = $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_attribute] ?? null;
+ $group_container_replace = $GLOBALS['egw_info']['server']['group_container_replace'] ?? '$1';
+
+ return [$group_container_attribute, $group_container_regexp, $group_container_replace];
+ }
+
+ /**
+ * Get container-name of a group, if configured
+ *
+ * @param array $group values for keys "account_dn" and "account_lid"
+ * @return string|null container-name or NULL
+ */
+ public static function container(array $group) : ?string
+ {
+ [$group_container_attribute, $group_container_regexp, $group_container_replace] = self::groupContainerAttributs();
+
+ if ($group_container_attribute && !empty($group[$group_container_attribute]) &&
+ preg_match($group_container_regexp, $group[$group_container_attribute], $matches) &&
+ ($container_name = ucfirst($matches[substr($group_container_replace, 1)] ?? '')))
+ {
+ return $container_name;
+ }
+ return null;
+ }
+
/**
* Internal functions not meant to use outside this class!!!
*/
diff --git a/api/src/Contacts/Sql.php b/api/src/Contacts/Sql.php
index 76f8e6cc42..554e34057a 100644
--- a/api/src/Contacts/Sql.php
+++ b/api/src/Contacts/Sql.php
@@ -648,7 +648,7 @@ class Sql extends Api\Storage
}
$extra_cols[] = $table.$column.' '.$matches[2];
//_debug_array($matches);
- if (!empty($order_by) && $table) // postgres requires explizit order by
+ if (!empty($order_by) && $table) // postgres requires explicit order by
{
$order_by = str_replace($matches[0],$table.$column.' '.$matches[2].' '.$matches[3].$matches[4],$order_by);
}
@@ -700,6 +700,21 @@ class Sql extends Api\Storage
}
unset($filter['shared_with']);
+ // if we have regular expression based container-name AND use MariaDB/MySQL sort by it instead of account_dn
+ if (preg_match('/(^|,| )account_dn( |,)/', $order_by) && in_array("account_type='g'", $filter) &&
+ !empty($GLOBALS['egw_info']['server']['group_container_attribute']) && $this->db->Type === 'mysql' &&
+ in_array($group_container_attribute=$GLOBALS['egw_info']['server']['group_container_attribute'], ['account_dn', 'account_lid']))
+ {
+ [, $group_container_regexp, $group_container_replace] = Api\Accounts::groupContainerAttributs();
+ [,$regexp,] = explode('/', $group_container_regexp);
+ if ($regexp[0] !== '^') $regexp = ($regexp[0] === ',' ? '^[^,]+' : '^.*').$regexp;
+ if (substr($regexp, -1) !== '$') $regexp .= '.*$';
+ $order = "COALESCE(REGEXP_REPLACE($group_container_attribute,".$this->db->quote($regexp).','.
+ $this->db->quote(str_replace('$', '\\', $group_container_replace))."), account_lid)";
+ $order_by = str_replace('account_dn', $order, $order_by);
+ $this->sanitize_order_by = false;
+ }
+
$rows =& parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count);
if ($start === false) $this->total = is_array($rows) ? count($rows) : 0; // so_sql sets total only for $start !== false!
diff --git a/api/src/Etemplate/Widget/Tree.php b/api/src/Etemplate/Widget/Tree.php
index 6c8b4cf008..8d6600a155 100644
--- a/api/src/Etemplate/Widget/Tree.php
+++ b/api/src/Etemplate/Widget/Tree.php
@@ -584,13 +584,6 @@ class Tree extends Etemplate\Widget
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(
@@ -600,9 +593,7 @@ class Tree extends Etemplate\Widget
'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)] ?? '')))
+ if (($container_name = Api\Accounts::container($group)))
{
foreach($children as &$container)
{