Admin - Add a group list

This commit is contained in:
nathangray 2017-09-19 11:11:21 -06:00
parent b5bda661a8
commit d590ad1fc1
5 changed files with 222 additions and 74 deletions

View File

@ -62,6 +62,16 @@ class admin_ui
'actions' => self::user_actions(),
'placeholder_actions' => array('add')
);
$content['groups'] = array(
'get_rows' => 'admin_ui::get_groups',
'no_cat' => true,
'no_filter' => true,
'no_filter2' => true,
'row_id' => 'account_id',
'actions' => self::group_actions(),
'placeholder_actions' => array('add')
);
//$content['msg'] = 'Hi Ralf ;-)';
$sel_options['tree'] = $this->tree_data();
$sel_options['filter'] = array('' => lang('All groups'));
@ -108,80 +118,16 @@ class admin_ui
*/
public static function tree_actions()
{
$user_actions = self::user_actions();
$actions = static::group_actions();
$actions = array(
'view' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Show members',
'enableId' => '^/groups/-\\d+',
'default' => true,
'group' => $group=1,
),
'add' => array(
'group' => $group,
)+$user_actions['add'],
'acl' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Access control',
'enableId' => '^/groups/-\\d+',
'url' => 'menuaction=admin.admin_acl.index&account_id=$id',
'popup' => '900x450',
'icon' => 'lock',
'group' => 2,
),
);
if (!$GLOBALS['egw']->acl->check('account_access',64,'admin')) // no rights to set ACL-rights
foreach($actions as $action_id => &$action)
{
$actions['deny'] = array(
'caption' => 'Deny access',
'enableId' => '^/groups/-\\d+',
'url' => 'menuaction=admin.admin_denyaccess.list_apps&account_id=$id',
'onExecute' => 'javaScript:app.admin.group',
'icon' => 'cancel',
'group' => 2,
);
}
$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'), Api\Hooks::implemented('edit_group')));
foreach($apps as $app)
if (!isset($action['enableId']) && !in_array($action_id, array('add')))
{
$GLOBALS['menuData'] = $data = array();
$data = Api\Hooks::single('edit_group', $app);
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
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']);
$action['enableId'] = '^/groups/-\\d+';
}
}
if (empty($item['icon'])) $item['icon'] = $app.'/navbar';
if (empty($item['group'])) $item['group'] = $group;
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;
}
}
return $actions;
}
@ -273,6 +219,90 @@ class admin_ui
return $actions;
}
/**
* Actions on groups
*
* @return array
*/
public static function group_actions()
{
$user_actions = self::user_actions();
$actions = array(
'view' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Show members',
'default' => true,
'group' => $group=1,
'allowOnMultiple' => false
),
'add' => array(
'group' => $group,
)+$user_actions['add'],
'acl' => array(
'onExecute' => 'javaScript:app.admin.group',
'caption' => 'Access control',
'url' => 'menuaction=admin.admin_acl.index&account_id=$id',
'popup' => '900x450',
'icon' => 'lock',
'group' => 2,
'allowOnMultiple' => false
),
);
if (!$GLOBALS['egw']->acl->check('account_access',64,'admin')) // no rights to set ACL-rights
{
$actions['deny'] = array(
'caption' => 'Deny access',
'url' => 'menuaction=admin.admin_denyaccess.list_apps&account_id=$id',
'onExecute' => 'javaScript:app.admin.group',
'icon' => 'cancel',
'group' => 2,
'allowOnMultiple' => false
);
}
$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'), Api\Hooks::implemented('edit_group')));
foreach($apps as $app)
{
$GLOBALS['menuData'] = $data = array();
$data = Api\Hooks::single('edit_group', $app);
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.group';
if (!isset($item['allowOnMultiple'])) $item['allowOnMultiple'] = false;
$actions[$item['id']] = $item;
}
}
return $actions;
}
/**
* Callback for nextmatch to fetch users
*
@ -318,6 +348,49 @@ class admin_ui
return self::$accounts->total;
}
/**
* Callback for the nextmatch to get groups
*/
public static function get_groups(&$query, &$rows)
{
$groups = $GLOBALS['egw']->accounts->search(array(
'type' => 'groups',
'order' => $query['order'],
'sort' => $query['sort'],
'start' => (int)$query['start'],
'num_rows' => (int)$query['num_rows']
));
$apps = array();
foreach($GLOBALS['egw_info']['apps'] as $app => $data)
{
if (!$data['enabled'] || !$data['status'] || $data['status'] == 3)
{
continue; // do NOT show disabled apps, or our API (status = 3)
}
$apps[] = $app;
}
$rows = array();
foreach($groups as &$group)
{
$run_rights = $GLOBALS['egw']->acl->get_user_applications($group['account_id'], false, false);
foreach($apps as $app)
{
if((boolean)$run_rights[$app])
{
$group['apps'][] = $app;
}
}
$group['members'] = $GLOBALS['egw']->accounts->members($group['account_id'],true);
$rows[] = $group;
}
return $GLOBALS['egw']->accounts->total;
}
/**
* Autoload tree from $_GET['id'] on
*/

View File

@ -89,6 +89,8 @@ app.classes.admin = AppJS.extend(
case 'admin.index':
var iframe = this.iframe = this.et2.getWidgetById('iframe');
this.nm = this.et2.getWidgetById('nm');
this.groups = this.et2.getWidgetById('groups');
this.groups.set_disabled(true);
this.ajax_target = this.et2.getWidgetById('ajax_target');
if (iframe)
{
@ -176,6 +178,7 @@ app.classes.admin = AppJS.extend(
}
this.iframe.set_disabled(!_url || ajax);
this.nm.set_disabled(!!_url || ajax);
this.groups.set_disabled(true);
this.ajax_target.set_disabled(!ajax);
},
@ -343,12 +346,20 @@ app.classes.admin = AppJS.extend(
{
var link = _widget.getUserData(_id, 'link');
this.groups.set_disabled(true);
this.nm.set_disabled(false);
if (_id == '/accounts' || _id.substr(0, 8) == '/groups/')
{
this.load();
var parts = _id.split('/');
this.et2.getWidgetById('nm').applyFilters({ filter: parts[2] ? parts[2] : '', search: ''});
}
else if (_id === '/groups')
{
this.load();
this.group_list();
}
else if (typeof link == 'undefined')
{
_widget.openItem(_id, 'toggle');
@ -364,6 +375,16 @@ app.classes.admin = AppJS.extend(
}
},
/**
* Show the group list in the main window
*/
group_list: function group_list()
{
this.nm.set_disabled(true);
this.groups.set_disabled(false);
},
/**
* View, edit or delete a group callback for tree
*
@ -372,14 +393,17 @@ app.classes.admin = AppJS.extend(
*/
group: function(_action, _senders)
{
// Tree IDs look like /groups/ID, nm uses admin::ID
var from_nm = _senders[0].id.indexOf('::') > 0;
var account_id = _senders[0].id.split(from_nm ? '::' : '/')[from_nm ? 1 : 2];
switch(_action.id)
{
case 'view':
this.run(_senders[0].id, this.et2.getWidgetById('tree'));
this.run(from_nm ? '/groups/'+account_id : _senders[0].id, this.et2.getWidgetById('tree'));
break;
case 'delete':
var account_id = _senders[0].id.split('/')[2];
this.egw.json('admin_account::ajax_delete_group', [account_id]).sendRequest();
break;
@ -389,14 +413,14 @@ app.classes.admin = AppJS.extend(
alert('Missing url in action '+_action.id+'!');
break;
}
var url = _action.data.url.replace('$id', _senders[0].id.split('/')[2]);
var url = unescape(_action.data.url).replace('$id', account_id);
if (url[0] != '/' && url.substr(0, 4) != 'http')
{
url = this.egw.link('/index.php', url);
}
if (_action.data.popup)
if (_action.data.popup || _action.data.width && _action.data.height)
{
this.egw.open_link(url, '_blank', _action.data.popup);
this.egw.open_link(url, '_blank', _action.data.popup ? _action.data.popup : _action.data.width + 'x' + _action.data.height);
}
else
{

View File

@ -26,6 +26,12 @@ body {
background-color: white;
}
/** Group list */
#admin-index_groups div.innerContainer {
overflow: auto;
max-height: 7em;
}
tr.adminAccountInactive .adminStatus {
color: red;
}

View File

@ -46,9 +46,49 @@
</rows>
</grid>
</template>
<template id="admin.index.group" template="" lang="" group="0" version="1.9.001">
<grid width="100%">
<columns>
<column width="30%"/>
<column width="15%"/>
<column width="25%"/>
<column width="25%"/>
<column width="120"/>
</columns>
<rows>
<row>
<vbox>
<nextmatch-sortheader label="Group name" id="account_lid"/>
<nextmatch-sortheader label="Description" id="account_description"/>
</vbox>
<nextmatch-sortheader label="EMail" id="account_email"/>
<nextmatch-sortheader label="Members" id="account_members"/>
<nextmatch-sortheader label="Applications" id="apps"/>
<vbox>
<nextmatch-sortheader label="Created" id="account_created"/>
<nextmatch-sortheader label="Modified" id="account_modified"/>
</vbox>
</row>
<row class="$row_cont[status_class]">
<vbox>
<description id="${row}[account_lid]" no_lang="1"/>
<description id="${row}[account_description]" no_lang="1"/>
</vbox>
<url-email id="${row}[account_email]" readonly="true" no_lang="1" class="adminOverflowEllipsis"/>
<select-account id="${row}[members]" no_lang="1" readonly="true"/>
<select-app id="${row}[apps]" tags="true" readonly="true"/>
<vbox>
<date id="${row}[account_created]" readonly="true"/>
<date id="${row}[account_modified]" readonly="true"/>
</vbox>
</row>
</rows>
</grid>
</template>
<template id="admin.index" template="" lang="" group="0" version="1.9.001">
<tree autoloading="admin_ui::ajax_tree" id="tree" onclick="app.admin.run" parent_node="admin_tree_target" std_images="bullet"/>
<nextmatch id="nm" template="admin.index.rows" header_left="admin.index.add"/>
<nextmatch id="groups" template="admin.index.group"/>
<iframe frameborder="1" height="100%" id="iframe" scrolling="auto" width="100%" disabled="true"/>
<box id="ajax_target" height="99%" disabled="true"/>
</template>

View File

@ -36,6 +36,11 @@ body {
#admin_iframe {
background-color: white;
}
/** Group list */
#admin-index_groups div.innerContainer {
overflow: auto;
max-height: 5em;
}
tr.adminAccountInactive .adminStatus {
color: red;
}