diff --git a/application/controllers/UserController.php b/application/controllers/UserController.php
index 217859574..3fe3dd604 100644
--- a/application/controllers/UserController.php
+++ b/application/controllers/UserController.php
@@ -7,7 +7,10 @@ use Icinga\Application\Config;
use Icinga\Application\Logger;
use Icinga\Authentication\User\UserBackend;
use Icinga\Authentication\User\UserBackendInterface;
+use Icinga\Authentication\UserGroup\UserGroupBackend;
use Icinga\Forms\Config\UserForm;
+use Icinga\Data\DataArray\ArrayDatasource;
+use Icinga\User;
use Icinga\Web\Controller;
use Icinga\Web\Form;
use Icinga\Web\Notification;
@@ -114,8 +117,53 @@ class UserController extends Controller
$this->httpNotFound(sprintf($this->translate('User "%s" not found'), $userName));
}
+ $memberships = $this->loadMemberships(new User($userName))->select();
+
+ $filterEditor = Widget::create('filterEditor')
+ ->setQuery($memberships)
+ ->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'user')
+ ->ignoreParams('page')
+ ->handleRequest($this->getRequest());
+ $memberships->applyFilter($filterEditor->getFilter());
+
+ $this->setupFilterControl($filterEditor);
+ $this->setupPaginationControl($memberships);
+ $this->setupLimitControl();
+ $this->setupSortControl(
+ array(
+ 'group_name' => $this->translate('Group')
+ ),
+ $memberships
+ );
+
$this->view->user = $user;
$this->view->backend = $backend;
+ $this->view->memberships = $memberships;
+
+ $removeForm = new Form();
+ $removeForm->setUidDisabled();
+ $removeForm->addElement('hidden', 'user_name', array(
+ 'isArray' => true,
+ 'value' => $userName,
+ 'decorators' => array('ViewHelper')
+ ));
+ $removeForm->addElement('hidden', 'redirect', array(
+ 'value' => Url::fromPath('user/show', array(
+ 'backend' => $backend->getName(),
+ 'user' => $userName
+ )),
+ 'decorators' => array('ViewHelper')
+ ));
+ $removeForm->addElement('button', 'btn_submit', array(
+ 'escape' => false,
+ 'type' => 'submit',
+ 'class' => 'link-like',
+ 'value' => 'btn_submit',
+ 'decorators' => array('ViewHelper'),
+ 'label' => $this->view->icon('trash'),
+ 'title' => $this->translate('Cancel this membership')
+ ));
+ $this->view->removeForm = $removeForm;
}
/**
@@ -176,6 +224,29 @@ class UserController extends Controller
$this->render('form');
}
+ /**
+ * Fetch and return the given user's groups from all user group backends
+ *
+ * @param User $user
+ *
+ * @return ArrayDatasource
+ */
+ protected function loadMemberships(User $user)
+ {
+ $groups = array();
+ foreach (Config::app('groups') as $backendName => $backendConfig) {
+ $backend = UserGroupBackend::create($backendName, $backendConfig);
+ foreach ($backend->getMemberships($user) as $groupName) {
+ $groups[] = (object) array(
+ 'group_name' => $groupName,
+ 'backend' => $backend
+ );
+ }
+ }
+
+ return new ArrayDatasource($groups);
+ }
+
/**
* Return all user backends implementing the given interface
*
diff --git a/application/views/scripts/user/show.phtml b/application/views/scripts/user/show.phtml
index 00b242512..cd8801b1a 100644
--- a/application/views/scripts/user/show.phtml
+++ b/application/views/scripts/user/show.phtml
@@ -1,6 +1,7 @@
-
- compact): ?>
- = $tabs->showOnlyCloseButton(); ?>
-
+ compact): ?>
+ = $tabs->showOnlyCloseButton(); ?>
+
+ compact): ?>
+ = $this->sortBox; ?>
+
+ = $this->limiter; ?>
+ = $this->paginator; ?>
+ compact): ?>
+ = $this->filterEditor; ?>
+
-
+
+ 0): ?>
+
+
+
+ | = $this->translate('Group'); ?> |
+ = $this->translate('Cancel', 'group.membership'); ?> |
+
+
+
+
+
+ | = $this->qlink($membership->group_name, 'group/show', array(
+ 'backend' => $membership->backend->getName(),
+ 'group' => $membership->group_name
+ ), array(
+ 'title' => sprintf($this->translate('Show detailed information for group %s'), $membership->group_name)
+ )); ?> |
+
+ backend instanceof Reducible): ?>
+ = $removeForm->setAction($this->url('group/removemember', array(
+ 'backend' => $membership->backend->getName(),
+ 'group' => $membership->group_name
+ ))); ?>
+
+ -
+
+ |
+
+
+
+
+
+
= $this->translate('No memberships found matching the filter'); ?>
+
+= $this->qlink($this->translate('Create new membership'), 'user/createmembership', array(
+ 'user' => $user->user_name
+), array(
+ 'icon' => 'plus',
+ 'data-base-target' => '_next',
+ 'class' => 'membership-create'
+)); ?>
\ No newline at end of file
diff --git a/public/css/icinga/main-content.less b/public/css/icinga/main-content.less
index 603466f67..4d5c4c896 100644
--- a/public/css/icinga/main-content.less
+++ b/public/css/icinga/main-content.less
@@ -228,6 +228,7 @@ div.content.users {
div.controls div.user-header {
border-bottom: 2px solid @colorPetrol;
+ margin-bottom: 1em;
.user-name {
display: inline-block;
@@ -241,6 +242,33 @@ div.controls div.user-header {
}
}
+div.content.memberships {
+ table.membership-list {
+ th.membership-cancel {
+ width: 8em;
+ padding-right: 0.5em;
+ text-align: right;
+ }
+
+ td.membership-cancel {
+ text-align: right;
+
+ form button.link-like {
+ color: inherit;
+ }
+ }
+ }
+
+ p {
+ margin-top: 0;
+ }
+
+ a.membership-create {
+ display: block;
+ margin-top: 1em;
+ }
+}
+
div.content.groups {
table.group-list {
th.group-remove {