Implement new search field to add user as group member

* Make AddMemberForm an Ipl form extending `SimpleSearchField`
This commit is contained in:
Sukhwinder Dhillon 2022-10-20 11:41:30 +02:00
parent 9c96a80ceb
commit 2adad04bf5
2 changed files with 57 additions and 113 deletions

View File

@ -9,6 +9,7 @@ use Icinga\Authentication\User\DomainAwareInterface;
use Icinga\Data\DataArray\ArrayDatasource; use Icinga\Data\DataArray\ArrayDatasource;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Data\Reducible; use Icinga\Data\Reducible;
use Icinga\Data\UserSuggestions;
use Icinga\Exception\NotFoundError; use Icinga\Exception\NotFoundError;
use Icinga\Forms\Config\UserGroup\AddMemberForm; use Icinga\Forms\Config\UserGroup\AddMemberForm;
use Icinga\Forms\Config\UserGroup\UserGroupForm; use Icinga\Forms\Config\UserGroup\UserGroupForm;
@ -17,7 +18,7 @@ use Icinga\Web\Controller\AuthBackendController;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Notification; use Icinga\Web\Notification;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Web\Widget; use ipl\Web\Url as IplUrl;
class GroupController extends AuthBackendController class GroupController extends AuthBackendController
{ {
@ -224,24 +225,50 @@ class GroupController extends AuthBackendController
{ {
$this->assertPermission('config/access-control/groups'); $this->assertPermission('config/access-control/groups');
$groupName = $this->params->getRequired('group'); $groupName = $this->params->getRequired('group');
$backend = $this->getUserGroupBackend($this->params->getRequired('backend'), 'Icinga\Data\Extensible'); $backend = $this->getUserGroupBackend(
$this->params->getRequired('backend'),
'Icinga\Data\Extensible'
);
$form = new AddMemberForm(); $form = (new AddMemberForm())
$form->setDataSource($this->fetchUsers())
->setBackend($backend) ->setBackend($backend)
->setGroupName($groupName) ->setGroupName($groupName)
->setRedirectUrl( ->setRedirectUrl(
Url::fromPath('group/show', array('backend' => $backend->getName(), 'group' => $groupName)) IplUrl::fromPath('group/show', ['backend' => $backend->getName(), 'group' => $groupName])
) )
->setUidDisabled(); ->setSuggestionUrl(IplUrl::fromPath(
'group/complete',
[
'_disableLayout' => true,
'showCompact' => true,
'backend' => $this->params->getRequired('backend'),
'group' => $groupName
]
));
try { $form->on(AddMemberForm::ON_SUCCESS, function ($form) {
$form->handleRequest(); $this->getResponse()->redirectAndExit($form->getRedirectUrl());
} catch (NotFoundError $_) { })->handleRequest($this->getServerRequest());
$this->httpNotFound(sprintf($this->translate('Group "%s" not found'), $groupName));
}
$this->renderForm($form, $this->translate('New User Group Member')); $this->addTitleTab($this->translate('New User Group Member'));
$this->addContent($form);
}
public function completeAction()
{
$backend = $this->getUserGroupBackend(
$this->params->getRequired('backend'),
'Icinga\Data\Extensible'
);
$groupName = $this->params->getRequired('group');
$suggestions = (new UserSuggestions())
->setUserGroupName($groupName)
->setUserGroupBackend($backend)
->setUserBackends($this->loadUserBackends('Icinga\Data\Selectable'))
->forRequest($this->getServerRequest());
$this->getDocument()->addHtml($suggestions);
} }
/** /**

View File

@ -1,28 +1,18 @@
<?php <?php
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ /* Icinga Web 2 | (c) 2015 Icinga GmbH | GPLv2+ */
namespace Icinga\Forms\Config\UserGroup; namespace Icinga\Forms\Config\UserGroup;
use Exception; use Exception;
use Icinga\Data\Extensible; use Icinga\Data\Extensible;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Selectable;
use Icinga\Exception\NotFoundError;
use Icinga\Web\Form;
use Icinga\Web\Notification; use Icinga\Web\Notification;
use ipl\Web\Control\SimpleSearchField;
/** /**
* Form for adding one or more group members * Form for adding one or more group members
*/ */
class AddMemberForm extends Form class AddMemberForm extends SimpleSearchField
{ {
/**
* The data source to fetch users from
*
* @var Selectable
*/
protected $ds;
/** /**
* The user group backend to use * The user group backend to use
* *
@ -37,19 +27,6 @@ class AddMemberForm extends Form
*/ */
protected $groupName; protected $groupName;
/**
* Set the data source to fetch users from
*
* @param Selectable $ds
*
* @return $this
*/
public function setDataSource(Selectable $ds)
{
$this->ds = $ds;
return $this;
}
/** /**
* Set the user group backend to use * Set the user group backend to use
* *
@ -76,74 +53,18 @@ class AddMemberForm extends Form
return $this; return $this;
} }
/**
* Create and add elements to this form
*
* @param array $formData The data sent by the user
*/
public function createElements(array $formData)
{
// TODO(jom): Fetching already existing members to prevent the user from mistakenly creating duplicate
// memberships (no matter whether the data source permits it or not, a member does never need to be
// added more than once) should be kept at backend level (GroupController::fetchUsers) but this does
// not work currently as our ldap protocol stuff is unable to handle our filter implementation..
$members = $this->backend
->select()
->from('group_membership', array('user_name'))
->where('group_name', $this->groupName)
->fetchColumn();
$filter = empty($members) ? Filter::matchAll() : Filter::not(Filter::where('user_name', $members));
$users = $this->ds->select()->from('user', array('user_name'))->applyFilter($filter)->fetchColumn();
if (! empty($users)) {
$this->addElement(
'multiselect',
'user_name',
array(
'multiOptions' => array_combine($users, $users),
'label' => $this->translate('Backend Users'),
'description' => $this->translate(
'Select one or more users (fetched from your user backends) to add as group member'
),
'class' => 'grant-permissions'
)
);
}
$this->addElement(
'textarea',
'users',
array(
'required' => empty($users),
'label' => $this->translate('Users'),
'description' => $this->translate(
'Provide one or more usernames separated by comma to add as group member'
)
)
);
$this->setTitle(sprintf($this->translate('Add members for group %s'), $this->groupName));
$this->setSubmitLabel($this->translate('Add'));
}
/**
* Insert the members for the group
*
* @return bool
*/
public function onSuccess() public function onSuccess()
{ {
$userNames = $this->getValue('user_name') ?: array(); $q = $this->getValue($this->getSearchParameter(), '');
if (($users = $this->getValue('users'))) {
$userNames = array_merge($userNames, array_map('trim', explode(',', $users))); $userNames = array_unique(array_filter(
} array_map('trim', explode(self::TERM_SEPARATOR, rawurldecode($q)))
));
if (empty($userNames)) { if (empty($userNames)) {
$this->info($this->translate( Notification::info(t('Please provide at least one username'));
'Please provide at least one username, either by choosing one '
. 'in the list or by manually typing one in the text box below' return;
));
return false;
} }
$single = null; $single = null;
@ -151,32 +72,28 @@ class AddMemberForm extends Form
try { try {
$this->backend->insert( $this->backend->insert(
'group_membership', 'group_membership',
array( [
'group_name' => $this->groupName, 'group_name' => $this->groupName,
'user_name' => $userName 'user_name' => $userName
) ]
); );
} catch (NotFoundError $e) {
throw $e; // Trigger 404, the group name is initially accessed as GET parameter
} catch (Exception $e) { } catch (Exception $e) {
Notification::error(sprintf( Notification::error(sprintf(
$this->translate('Failed to add "%s" as group member for "%s"'), t('Failed to add "%s" as group member for "%s"'),
$userName, $userName,
$this->groupName $this->groupName
)); ));
$this->error($e->getMessage());
return false; return;
} }
$single = $single === null; $single = $single === null;
} }
if ($single) { if ($single) {
Notification::success(sprintf($this->translate('Group member "%s" added successfully'), $userName)); Notification::success(sprintf(t('Group member "%s" added successfully'), $userName));
} else { } else {
Notification::success($this->translate('Group members added successfully')); Notification::success(t('Group members added successfully'));
} }
return true;
} }
} }