get group actions from edit_group hook

This commit is contained in:
Ralf Becker 2014-03-27 19:00:52 +00:00
parent 2282d600c0
commit fe83c07b50
7 changed files with 361 additions and 251 deletions

View File

@ -46,6 +46,8 @@ class admin_account
if ($content['id']) // existing account
{
// invalidate account, before reading it, to code with changed to DB or LDAP outside EGw
accounts::cache_invalidate((int)$content['account_id']);
if (!($account = $GLOBALS['egw']->accounts->read($content['account_id'])))
{
throw new egw_exception_not_found('Account data NOT found!');
@ -74,8 +76,11 @@ class admin_account
'changepassword' => true, //old default: (bool)$GLOBALS['egw_info']['server']['change_pwd_every_x_days'],
'mustchangepassword' => false,
'account_primary_group' => $GLOBALS['egw']->accounts->name2id('Default'),
'homedirectory' => $GLOBALS['egw_info']['server']['ldap_account_home'],
'loginshell' => $GLOBALS['egw_info']['server']['ldap_account_shell'],
);
}
$account['ldap_extra_attributes'] = $GLOBALS['egw_info']['server']['ldap_extra_attributes'];
$readonlys = array();
if ($deny_edit)

View File

@ -0,0 +1,179 @@
<?php
/**
* EGroupware Admin: Hooks
*
* @link http://www.egroupware.org
* @author Stefan Becker <StefanBecker-AT-outdoor-training.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package admin
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* Static hooks for admin application
*/
class admin_hooks
{
/**
* Functions callable via menuaction
*
* @var unknown_type
*/
var $public_functions = array(
'register_all_hooks' => True,
);
/**
* hooks to build projectmanager's sidebox-menu
*
* @param string/array $args hook args
*/
static function all_hooks($args)
{
unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']);
if (!isset($_GET['menuaction']) && substr($_SERVER['PHP_SELF'],-16) == '/admin/index.php')
{
admin_statistics::check();
}
$appname = 'admin';
$location = is_array($args) ? $args['location'] : $args;
if ($location == 'sidebox_menu')
{
// Destination div for folder tree
$file[] = array(
'no_lang' => true,
'text' => '<span id="admin_tree_target" class="admin_tree" />',
'link' => false,
'icon' => false
);
display_sidebox($appname,lang('Admin'),$file);
return;
}
if ($GLOBALS['egw_info']['user']['apps']['admin'])
{
if (! $GLOBALS['egw']->acl->check('site_config_access',1,'admin'))
{
$file['Site Configuration'] = egw::link('/index.php','menuaction=admin.uiconfig.index&appname=admin');
}
if (! $GLOBALS['egw']->acl->check('account_access',1,'admin'))
{
$file['User Accounts'] = array(
'id' => '/accounts',
'icon' => common::image('addressbook', 'accounts'),
'link' => egw::link('/index.php','menuaction=admin.uiaccounts.list_users'),
);
}
if (! $GLOBALS['egw']->acl->check('account_access',16,'admin'))
{
$file['Bulk password reset'] = egw::link('/index.php','menuaction=admin.admin_passwordreset.index');
}
if (! $GLOBALS['egw']->acl->check('group_access',1,'admin'))
{
$file['User Groups'] = array(
'id' => '/groups',
'icon' => common::image('addressbook', 'group'),
'child' => 1,
);
}
if (! $GLOBALS['egw']->acl->check('applications_access',1,'admin'))
{
$file['Applications'] = egw::link('/index.php','menuaction=admin.admin_applications.index');
}
if (! $GLOBALS['egw']->acl->check('global_categories_access',1,'admin'))
{
$file['Global Categories'] = egw::link('/index.php','menuaction=admin.admin_categories.index&appname=phpgw');
}
if (!$GLOBALS['egw']->acl->check('mainscreen_message_access',1,'admin') || !$GLOBALS['egw']->acl->check('mainscreen_message_access',2,'admin'))
{
$file['Change Main Screen Message'] = egw::link('/index.php','menuaction=admin.uimainscreen.index');
}
if (! $GLOBALS['egw']->acl->check('current_sessions_access',1,'admin'))
{
$file['View Sessions'] = egw::link('/index.php','menuaction=admin.admin_accesslog.sessions');
}
if (! $GLOBALS['egw']->acl->check('access_log_access',1,'admin'))
{
$file['View Access Log'] = egw::link('/index.php','menuaction=admin.admin_accesslog.index');
}
if (! $GLOBALS['egw']->acl->check('error_log_access',1,'admin'))
{
$file['View Error Log'] = egw::link('/index.php','menuaction=admin.uilog.list_log');
}
if (! $GLOBALS['egw']->acl->check('applications_access',16,'admin'))
{
$file['Clear cache and register hooks'] = egw::link('/index.php','menuaction=admin.admin_hooks.register_all_hooks');
}
if (! $GLOBALS['egw']->acl->check('asyncservice_access',1,'admin'))
{
$file['Asynchronous timed services'] = egw::link('/index.php','menuaction=admin.uiasyncservice.index');
}
if (! $GLOBALS['egw']->acl->check('db_backup_access',1,'admin'))
{
$file['DB backup and restore'] = egw::link('/index.php','menuaction=admin.admin_db_backup.index');
}
if (! $GLOBALS['egw']->acl->check('info_access',1,'admin'))
{
$file['phpInfo'] = "javascript:egw_openWindowCentered2('" . egw::link('/admin/phpinfo.php','',false) . "','phpinfoWindow',700,600,'yes')";
}
$file['Admin queue and history'] = egw::link('/index.php','menuaction=admin.admin_cmds.index');
$file['Remote administration instances'] = egw::link('/index.php','menuaction=admin.admin_cmds.remotes');
$file['Custom translation'] = egw::link('/index.php','menuaction=admin.admin_customtranslation.index');
$file['Submit statistic information'] = egw::link('/index.php','menuaction=admin.admin_statistics.submit');
if ($location == 'admin')
{
display_section($appname,$file);
}
else
{
foreach($file as &$url)
{
if (is_array($url) && $url['link']) $url = $url['link'];
}
display_sidebox($appname,lang('Admin'),$file);
}
}
}
/**
* Register all hooks
*/
function register_all_hooks()
{
if ($GLOBALS['egw']->acl->check('applications_access',16,'admin'))
{
$GLOBALS['egw']->redirect_link('/index.php');
}
egw_cache::flush(egw_cache::INSTANCE);
$GLOBALS['egw']->hooks->register_all_hooks();
common::delete_image_map();
if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited
{
$GLOBALS['egw']->invalidate_session_cache(); // in case with cache the egw_info array in the session
}
// allow apps to hook into "Admin >> Clear cache and register hooks"
$GLOBALS['egw']->hooks->process('clear_cache', array(), true);
$GLOBALS['egw']->redirect_link('/admin/index.php');
}
}

View File

@ -6,172 +6,14 @@
* @author Stefan Becker <StefanBecker-AT-outdoor-training.de>
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package admin
* @deprecated use standard admin_hooks class
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* Static hooks for admin application
* Old class-name to ease updates
*
* @deprecated use standard admin_hooks class
*/
class admin_prefs_sidebox_hooks
{
/**
* Functions callable via menuaction
*
* @var unknown_type
*/
var $public_functions = array(
'register_all_hooks' => True,
);
/**
* hooks to build projectmanager's sidebox-menu
*
* @param string/array $args hook args
*/
static function all_hooks($args)
{
unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']);
if (!isset($_GET['menuaction']) && substr($_SERVER['PHP_SELF'],-16) == '/admin/index.php')
{
admin_statistics::check();
}
$appname = 'admin';
$location = is_array($args) ? $args['location'] : $args;
if ($location == 'sidebox_menu')
{
// Destination div for folder tree
$file[] = array(
'no_lang' => true,
'text' => '<span id="admin_tree_target" class="admin_tree" />',
'link' => false,
'icon' => false
);
display_sidebox($appname,lang('Admin'),$file);
return;
}
if ($GLOBALS['egw_info']['user']['apps']['admin'])
{
if (! $GLOBALS['egw']->acl->check('site_config_access',1,'admin'))
{
$file['Site Configuration'] = egw::link('/index.php','menuaction=admin.uiconfig.index&appname=admin');
}
if (! $GLOBALS['egw']->acl->check('account_access',1,'admin'))
{
$file['User Accounts'] = array(
'id' => '/accounts',
'icon' => common::image('addressbook', 'accounts'),
'link' => egw::link('/index.php','menuaction=admin.uiaccounts.list_users'),
);
}
if (! $GLOBALS['egw']->acl->check('account_access',16,'admin'))
{
$file['Bulk password reset'] = egw::link('/index.php','menuaction=admin.admin_passwordreset.index');
}
if (! $GLOBALS['egw']->acl->check('group_access',1,'admin'))
{
$file['User Groups'] = array(
'id' => '/groups',
'icon' => common::image('addressbook', 'group'),
'child' => 1,
'link' => egw::link('/index.php','menuaction=admin.uiaccounts.list_groups'),
);
}
if (! $GLOBALS['egw']->acl->check('applications_access',1,'admin'))
{
$file['Applications'] = egw::link('/index.php','menuaction=admin.admin_applications.index');
}
if (! $GLOBALS['egw']->acl->check('global_categories_access',1,'admin'))
{
$file['Global Categories'] = egw::link('/index.php','menuaction=admin.admin_categories.index&appname=phpgw');
}
if (!$GLOBALS['egw']->acl->check('mainscreen_message_access',1,'admin') || !$GLOBALS['egw']->acl->check('mainscreen_message_access',2,'admin'))
{
$file['Change Main Screen Message'] = egw::link('/index.php','menuaction=admin.uimainscreen.index');
}
if (! $GLOBALS['egw']->acl->check('current_sessions_access',1,'admin'))
{
$file['View Sessions'] = egw::link('/index.php','menuaction=admin.admin_accesslog.sessions');
}
if (! $GLOBALS['egw']->acl->check('access_log_access',1,'admin'))
{
$file['View Access Log'] = egw::link('/index.php','menuaction=admin.admin_accesslog.index');
}
if (! $GLOBALS['egw']->acl->check('error_log_access',1,'admin'))
{
$file['View Error Log'] = egw::link('/index.php','menuaction=admin.uilog.list_log');
}
if (! $GLOBALS['egw']->acl->check('applications_access',16,'admin'))
{
$file['Clear cache and register hooks'] = egw::link('/index.php','menuaction=admin.admin_prefs_sidebox_hooks.register_all_hooks');
}
if (! $GLOBALS['egw']->acl->check('asyncservice_access',1,'admin'))
{
$file['Asynchronous timed services'] = egw::link('/index.php','menuaction=admin.uiasyncservice.index');
}
if (! $GLOBALS['egw']->acl->check('db_backup_access',1,'admin'))
{
$file['DB backup and restore'] = egw::link('/index.php','menuaction=admin.admin_db_backup.index');
}
if (! $GLOBALS['egw']->acl->check('info_access',1,'admin'))
{
$file['phpInfo'] = "javascript:egw_openWindowCentered2('" . egw::link('/admin/phpinfo.php','',false) . "','phpinfoWindow',700,600,'yes')";
}
$file['Admin queue and history'] = egw::link('/index.php','menuaction=admin.admin_cmds.index');
$file['Remote administration instances'] = egw::link('/index.php','menuaction=admin.admin_cmds.remotes');
$file['Custom translation'] = egw::link('/index.php','menuaction=admin.admin_customtranslation.index');
$file['Submit statistic information'] = egw::link('/index.php','menuaction=admin.admin_statistics.submit');
if ($location == 'admin')
{
display_section($appname,$file);
}
else
{
foreach($file as &$url) if (is_array($url) && $url['link']) $url = $url['link'];
display_sidebox($appname,lang('Admin'),$file);
}
}
}
/**
* Register all hooks
*/
function register_all_hooks()
{
if ($GLOBALS['egw']->acl->check('applications_access',16,'admin'))
{
$GLOBALS['egw']->redirect_link('/index.php');
}
egw_cache::flush(egw_cache::INSTANCE);
$GLOBALS['egw']->hooks->register_all_hooks();
common::delete_image_map();
if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited
{
$GLOBALS['egw']->invalidate_session_cache(); // in case with cache the egw_info array in the session
}
// allow apps to hook into "Admin >> Clear cache and register hooks"
$GLOBALS['egw']->hooks->process('clear_cache', array(), true);
$GLOBALS['egw']->redirect_link('/admin/index.php');
}
}
class admin_prefs_sidebox_hooks extends admin_hooks {}

View File

@ -73,33 +73,7 @@ class admin_ui
$sel_options['account_primary_group'] = $sel_options['filter'];
unset($sel_options['account_primary_group']['']);
$actions = array(
'view' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Show members',
'enableId' => '^/groups/-\\d+',
'default' => true,
),
'edit' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Edit group',
'enableId' => '^/groups/-\\d+',
),
'acl' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Access control',
'enableId' => '^/groups/-\\d+',
'icon' => 'lock',
),
'add' => $content['nm']['actions']['add'],
'delete' => array(
'onExecute' => 'javaScript:app.admin.group',
'confirm' => 'Delete this group',
'caption' => 'Delete group',
'enableId' => '^/groups/-\\d+',
),
);
$tpl->setElementAttribute('tree', 'actions', $actions);
$tpl->setElementAttribute('tree', 'actions', self::tree_actions());
if (!empty($_GET['load']))
{
@ -118,56 +92,49 @@ class admin_ui
}
/**
* Actions on users
* Actions on tree / groups
*
* @return array
*/
public static function user_actions()
public static function tree_actions()
{
$user_actions = self::user_actions();
$actions = array(
'edit' => array(
'caption' => 'Open',
'view' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Show members',
'enableId' => '^/groups/-\\d+',
'default' => true,
'allowOnMultiple' => false,
'onExecute' => 'javaScript:app.admin.account',
'group' => $group=0,
'group' => $group=1,
),
'add' => array(
'caption' => 'Add user',
'onExecute' => 'javaScript:app.admin.account',
'group' => $group,
)+$user_actions['add'],
'edit' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Edit group',
'enableId' => '^/groups/-\\d+',
'url' => 'menuaction=admin.uiaccounts.edit_group&account_id=$id',
'group' => 2,
),
'acl' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Access control',
'allowOnMultiple' => false,
'url' => 'menuaction=admin.admin_acl.index&account_id=$id',
'group' => $group,
'onExecute' => 'javaScript:app.admin.iframe_location',
'enableId' => '^/groups/-\\d+',
'icon' => 'lock',
'group' => 2,
),
);
// generate urls for add/edit accounts via addressbook
$edit = egw_link::get_registry('addressbook', 'edit');
$edit['account_id'] = '$id';
foreach($edit as $name => $val)
{
$actions['edit']['url'] .= ($actions['edit']['url'] ? '&' : '').$name.'='.$val;
}
unset($edit['account_id']);
$edit['owner'] = 0;
foreach($edit as $name => $val)
{
$actions['add']['url'] .= ($actions['edit']['url'] ? '&' : '').$name.'='.$val;
}
++$group;
$group = 5; // allow to place actions in different groups by hook, this is the default
// supporting both old way using $GLOBALS['menuData'] and new just returning data in hook
$apps = array_unique(array_merge(array('admin'), $GLOBALS['egw']->hooks->hook_implemented('edit_user')));
$apps = array_unique(array_merge(array('admin'), $GLOBALS['egw']->hooks->hook_implemented('edit_group')));
foreach($apps as $app)
{
if ($app == 'felamimail') continue; // disabled fmail for now, as it break whole admin, dono why
$GLOBALS['menuData'] = $data = array();
$data = $GLOBALS['egw']->hooks->single('edit_user', $app, true);
$data = $GLOBALS['egw']->hooks->single('edit_group', $app, true);
if (!is_array($data)) $data = $GLOBALS['menuData'];
//error_log(__METHOD__."() app $app returned ".array2string($data));
foreach($data as $item)
{
// allow hook to return "real" actions, but still support legacy: description, url, extradata, options
@ -192,17 +159,108 @@ if ($app == 'felamimail') continue; // disabled fmail for now, as it break whole
}
if (empty($item['icon'])) $item['icon'] = $app.'/navbar';
if (empty($item['group'])) $item['group'] = $group;
if (empty($item['onExecute'])) $item['onExecute'] = 'javaScript:app.admin.iframe_location';
if (empty($item['onExecute'])) $item['onExecute'] = 'javaScript:app.admin.group';
if (!isset($item['allowOnMultiple'])) $item['allowOnMultiple'] = false;
if (!isset($item['enableId'])) $item['enableId'] = '^/groups/-\\d+';
$actions[$item['id']] = $item;
}
}
$actions['delete'] = array(
'caption' => 'Delete',
'group' => ++$group,
'popup' => '400x200',
'url' => 'menuaction=admin.admin_account.delete&account_id=$id',
);
return $actions;
}
/**
* Actions on users
*
* @return array
*/
public static function user_actions()
{
static $actions = null;
if (!isset($actions))
{
$actions = array(
'edit' => array(
'caption' => 'Open',
'default' => true,
'allowOnMultiple' => false,
'onExecute' => 'javaScript:app.admin.account',
'group' => $group=0,
),
'add' => array(
'caption' => 'Add user',
'onExecute' => 'javaScript:app.admin.account',
'group' => $group,
),
'acl' => array(
'caption' => 'Access control',
'allowOnMultiple' => false,
'url' => 'menuaction=admin.admin_acl.index&account_id=$id',
'group' => $group,
'onExecute' => 'javaScript:app.admin.iframe_location',
'icon' => 'lock',
),
);
// generate urls for add/edit accounts via addressbook
$edit = egw_link::get_registry('addressbook', 'edit');
$edit['account_id'] = '$id';
foreach($edit as $name => $val)
{
$actions['edit']['url'] .= ($actions['edit']['url'] ? '&' : '').$name.'='.$val;
}
unset($edit['account_id']);
$edit['owner'] = 0;
foreach($edit as $name => $val)
{
$actions['add']['url'] .= ($actions['edit']['url'] ? '&' : '').$name.'='.$val;
}
++$group;
// supporting both old way using $GLOBALS['menuData'] and new just returning data in hook
$apps = array_unique(array_merge(array('admin'), $GLOBALS['egw']->hooks->hook_implemented('edit_user')));
foreach($apps as $app)
{
if ($app == 'felamimail') continue; // disabled fmail for now, as it break whole admin, dono why
$GLOBALS['menuData'] = $data = array();
$data = $GLOBALS['egw']->hooks->single('edit_user', $app, true);
if (!is_array($data)) $data = $GLOBALS['menuData'];
foreach($data as $item)
{
// allow hook to return "real" actions, but still support legacy: description, url, extradata, options
if (empty($item['caption']))
{
$item['caption'] = $item['description'];
unset($item['description']);
}
if (isset($item['url']) && isset($item['extradata']))
{
$item['url'] = $item['extradata'].'&account_id=$id';
$item['id'] = substr($item['extradata'], 11);
unset($item['extradata']);
$matches = null;
if ($item['options'] && preg_match('/(egw_openWindowCentered2?|window.open)\([^)]+,(\d+),(\d+).*(title="([^"]+)")?/', $item['options'], $matches))
{
$item['popup'] = $matches[2].'x'.$matches[3];
$item['onExecute'] = 'javaScript:nm_action';
if (isset($matches[5])) $item['tooltip'] = $matches[5];
unset($item['options']);
}
}
if (empty($item['icon'])) $item['icon'] = $app.'/navbar';
if (empty($item['group'])) $item['group'] = $group;
if (empty($item['onExecute'])) $item['onExecute'] = 'javaScript:app.admin.iframe_location';
if (!isset($item['allowOnMultiple'])) $item['allowOnMultiple'] = false;
$actions[$item['id']] = $item;
}
}
$actions['delete'] = array(
'caption' => 'Delete',
'group' => ++$group,
'popup' => '400x200',
'url' => 'menuaction=admin.admin_account.delete&account_id=$id',
);
}
//error_log(__METHOD__."() actions=".array2string($actions));
return $actions;
}

View File

@ -15,22 +15,29 @@
* @augments AppJS
*/
app.classes.admin = AppJS.extend(
/**
* @lends app.classes.admin
*/
{
appname: 'admin',
/**
* reference to splitter
*
* {et2_splitter}
*/
splitter: null,
/**
* reference to splitter
*
* {et2_iframe}
*/
iframe: null,
/**
* Constructor
*
* @memberOf app.filemanager
* @memberOf app.classes.admin
*/
init: function()
{
@ -262,14 +269,6 @@ app.classes.admin = AppJS.extend(
this.run(_senders[0].id, this.et2.getWidgetById('tree'));
break;
case 'edit':
this.splitter.dock();
this.iframe.set_src(egw.link('/index.php', {
menuaction: 'admin.uiaccounts.edit_group',
account_id: _senders[0].id.split('/')[2]
}));
break;
case 'delete':
var account_id = _senders[0].id.split('/')[2];
this.egw.json('admin_account::ajax_delete_group', [account_id]).sendRequest();
@ -282,6 +281,28 @@ app.classes.admin = AppJS.extend(
account_id: _senders[0].id.split('/')[2]
}));
break;
default:
if (!_action.data.url)
{
alert('Missing url in action '+_action.id+'!');
break;
}
var url = _action.data.url.replace('$id', _senders[0].id.split('/')[2]);
if (url[0] != '/' && url.substr(0, 4) != 'http')
{
url = this.egw.link('/index.php', url);
}
if (_action.data.popup)
{
this.egw.open_link(url, '_blank', _action.data.popup);
}
else
{
this.splitter.dock();
this.iframe.set_src(url);
}
break;
}
},
@ -385,15 +406,15 @@ app.classes.admin = AppJS.extend(
if (diff.length > 0)
{
var removed_cat_label = jQuery.map(select_owner.options.select_options, function (val, i)
{
for (j=0; j <= diff.length;j++)
{
if (diff[j] == val.value)
{
return val.label;
}
}
});
{
for (var j=0; j <= diff.length;j++)
{
if (diff[j] == val.value)
{
return val.label;
}
}
});
// Somebody will lose permission, give warning.
if(removed_cat_label)

View File

@ -37,13 +37,10 @@ $setup_info['admin']['hooks'] = array(
'after_navbar',
'config_validate',
'deleteaccount',
'view_user' => 'admin.uiaccounts.edit_view_user_hook',
'edit_user' => 'admin.uiaccounts.edit_view_user_hook',
'group_manager' => 'admin.uiaccounts.edit_group_hook',
'topmenu_info'
);
$setup_info['admin']['hooks']['admin'] = 'admin.admin_prefs_sidebox_hooks.all_hooks';
$setup_info['admin']['hooks']['sidebox_menu'] = 'admin.admin_prefs_sidebox_hooks.all_hooks';
$setup_info['admin']['hooks']['admin'] = 'admin.admin_hooks.all_hooks';
$setup_info['admin']['hooks']['sidebox_menu'] = 'admin.admin_hooks.all_hooks';
// add account tab to addressbook.edit
$setup_info['admin']['hooks']['addressbook_edit'] = 'admin.admin_account.addressbook_edit';

View File

@ -41,6 +41,14 @@
<checkbox id="anonymous" label="Anonymous user. Not shown in list sessions."/>
<description/>
</row>
<row disabled="!@ldap_extra_attributes">
<description value="Home directory" for="homedirectory"/>
<passwd id="homedirectory" class="et2_fullWidth"/>
<description/>
<description value="Login shell" for="loginshell"/>
<passwd id="Login shell" class="et2_fullWidth"/>
<description/>
</row>
<row>
<description value="Primary group" for="account_primary_group"/>
<select-account id="account_primary_group" account_type="groups" class="et2_fullWidth"/>
@ -51,7 +59,7 @@
</row>
<row>
<description value="Groups" for="groups"/>
<taglist-account account_type="groups" id="memberships" multiple="true" class="et2_fullWidth" span="4"/>
<select-account account_type="groups" id="memberships" multiple="true" class="et2_fullWidth" span="4" tags="true"/>
<description/>
</row>
<row disabled="!@account_id">