From b79bdea482bbd1720548eeda1a901a23430940fb Mon Sep 17 00:00:00 2001 From: Steve Boyd Date: Thu, 15 Sep 2022 15:06:59 +1200 Subject: [PATCH] API Convert SecurityAdmin to be a ModelAdmin Co-authored-by: Maxime Rainville --- client/dist/js/MemberImportForm.js | 2 +- client/src/legacy/MemberImportForm.js | 12 +- code/GroupImportForm.php | 121 ------- code/MemberImportForm.php | 146 --------- code/SecurityAdmin.php | 371 ++++++---------------- tests/behat/features/manage-users.feature | 45 ++- tests/php/SecurityAdminTest.php | 2 +- 7 files changed, 134 insertions(+), 565 deletions(-) delete mode 100644 code/GroupImportForm.php delete mode 100644 code/MemberImportForm.php diff --git a/client/dist/js/MemberImportForm.js b/client/dist/js/MemberImportForm.js index f16dd0871..3372bbd31 100644 --- a/client/dist/js/MemberImportForm.js +++ b/client/dist/js/MemberImportForm.js @@ -1 +1 @@ -webpackJsonp([2],{"./client/src/legacy/MemberImportForm.js":function(e,n,t){"use strict";var o=t(3);(function(e){return e&&e.__esModule?e:{default:e}})(o).default.entwine("ss",function(e){e(".import-form .advanced").entwine({onmatch:function(){this._super(),this.hide()},onunmatch:function(){this._super()}}),e(".import-form a.toggle-advanced").entwine({onclick:function(e){return this.parents("form:eq(0)").find(".advanced").toggle(),!1}})})}},["./client/src/legacy/MemberImportForm.js"]); \ No newline at end of file +webpackJsonp([2],{"./client/src/legacy/MemberImportForm.js":function(n,e,t){"use strict";var o=t(3);(function(n){return n&&n.__esModule?n:{default:n}})(o).default.entwine("ss",function(n){n("#Form_ImportForm .advanced").entwine({onmatch:function(){this._super(),this.hide()},onunmatch:function(){this._super()}}),n("#Form_ImportForm a.toggle-advanced").entwine({onclick:function(e){var t=n("#Form_ImportForm .advanced");return"none"===t.css("display")?t.show():t.hide(),!1}})})}},["./client/src/legacy/MemberImportForm.js"]); \ No newline at end of file diff --git a/client/src/legacy/MemberImportForm.js b/client/src/legacy/MemberImportForm.js index 065e68fa9..fc149a543 100644 --- a/client/src/legacy/MemberImportForm.js +++ b/client/src/legacy/MemberImportForm.js @@ -7,7 +7,7 @@ $.entwine('ss', function($){ /** * Class: .import-form .advanced */ - $('.import-form .advanced').entwine({ + $('#Form_ImportForm .advanced').entwine({ onmatch: function() { this._super(); @@ -21,13 +21,19 @@ $.entwine('ss', function($){ /** * Class: .import-form a.toggle-advanced */ - $('.import-form a.toggle-advanced').entwine({ + $('#Form_ImportForm a.toggle-advanced').entwine({ /** * Function: onclick */ onclick: function(e) { - this.parents('form:eq(0)').find('.advanced').toggle(); + let $el = $('#Form_ImportForm .advanced'); + // .toggle() not working for some strange reason, so doing manually + if ($el.css('display') === 'none') { + $el.show(); + } else { + $el.hide(); + } return false; } }); diff --git a/code/GroupImportForm.php b/code/GroupImportForm.php deleted file mode 100644 index 437c73cbb..000000000 --- a/code/GroupImportForm.php +++ /dev/null @@ -1,121 +0,0 @@ -Import one or more groups in CSV format (comma-separated values).' - . ' Show advanced usage

' - ); - - $importer = new GroupCsvBulkLoader(); - $importSpec = $importer->getImportSpec(); - - $columns = implode(', ', array_keys($importSpec['fields'] ?? [])); - $helpHtml .= _t( - __CLASS__ . '.Help2', - '
' - . '

Advanced usage

' - . '
    ' - . '
  • Allowed columns: {columns}
  • ' - . '
  • Existing groups are matched by their unique Code value, and updated with any new values from the ' - . 'imported file
  • ' - . '
  • Group hierarchies can be created by using a ParentCode column.
  • ' - . '
  • Permission codes can be assigned by the PermissionCode column. Existing permission codes are not ' - . 'cleared.
  • ' - . '
' - . '
', - ['columns' => $columns] - ); - - $fields = new FieldList( - new LiteralField('Help', $helpHtml), - $fileField = new FileField( - 'CsvFile', - DBField::create_field('HTMLFragment', _t( - MemberImportForm::class . '.FileFieldLabel', - 'CSV File (Allowed extensions: *.csv)' - )) - ) - ); - $fileField->getValidator()->setAllowedExtensions(['csv']); - } - - if (!$actions) { - $action = new FormAction('doImport', _t(MemberImportForm::class . '.BtnImport', 'Import from CSV')); - $action->addExtraClass('btn btn-outline-secondary font-icon-upload'); - $actions = new FieldList($action); - } - - if (!$validator) { - $validator = new RequiredFields('CsvFile'); - } - - parent::__construct($controller, $name, $fields, $actions, $validator); - - $this->addExtraClass('cms'); - $this->addExtraClass('import-form'); - } - - public function doImport($data, $form) - { - $loader = new GroupCsvBulkLoader(); - - // load file - $result = $loader->load($data['CsvFile']['tmp_name']); - - // result message - $msgArr = []; - if ($result->CreatedCount()) { - $msgArr[] = _t( - __CLASS__ . '.ResultCreated', - 'Created {count} groups', - ['count' => $result->CreatedCount()] - ); - } - if ($result->UpdatedCount()) { - $msgArr[] = _t( - __CLASS__ . '.ResultUpdated', - 'Updated {count} groups', - ['count' => $result->UpdatedCount()] - ); - } - if ($result->DeletedCount()) { - $msgArr[] = _t( - __CLASS__ . '.ResultDeleted', - 'Deleted {count} groups', - ['count' => $result->DeletedCount()] - ); - } - $msg = ($msgArr) ? implode(',', $msgArr) : _t(MemberImportForm::class . '.ResultNone', 'No changes'); - - $this->sessionMessage($msg, 'good'); - - $this->controller->redirectBack(); - } -} diff --git a/code/MemberImportForm.php b/code/MemberImportForm.php deleted file mode 100644 index f12566aa6..000000000 --- a/code/MemberImportForm.php +++ /dev/null @@ -1,146 +0,0 @@ -Import users in CSV format (comma-separated values).' - . ' Show advanced usage

' - ); - - $importer = new MemberCsvBulkLoader(); - $importSpec = $importer->getImportSpec(); - - $columns = implode(', ', array_keys($importSpec['fields'] ?? [])); - $helpHtml .= _t( - __CLASS__ . '.Help2', - '
' - . '

Advanced usage

' - . '
    ' - . '
  • Allowed columns: {columns}
  • ' - . '
  • Existing users are matched by their unique Code property, and updated with any new values from ' - . 'the imported file.
  • ' - . '
  • Groups can be assigned by the Groups column. Groups are identified by their Code property, ' - . 'multiple groups can be separated by comma. Existing group memberships are not cleared.
  • ' - . '
' - . '
', - ['columns' => $columns] - ); - - $fields = new FieldList( - new LiteralField('Help', $helpHtml), - $fileField = new FileField( - 'CsvFile', - DBField::create_field('HTMLFragment', _t( - __CLASS__ . '.FileFieldLabel', - 'CSV File (Allowed extensions: *.csv)' - )) - ) - ); - $fileField->getValidator()->setAllowedExtensions(['csv']); - } - - if (!$actions) { - $action = new FormAction('doImport', _t(__CLASS__ . '.BtnImport', 'Import from CSV')); - $action->addExtraClass('btn btn-outline-secondary font-icon-upload'); - $actions = new FieldList($action); - } - - if (!$validator) { - $validator = new RequiredFields('CsvFile'); - } - - parent::__construct($controller, $name, $fields, $actions, $validator); - - Requirements::javascript('silverstripe/admin:client/dist/js/vendor.js'); - Requirements::javascript('silverstripe/admin:client/dist/js/MemberImportForm.js'); - Requirements::css('silverstripe/admin:client/dist/styles/bundle.css'); - - $this->addExtraClass('cms'); - $this->addExtraClass('import-form'); - } - - public function doImport($data, $form) - { - $loader = new MemberCsvBulkLoader(); - - // optionally set group relation - if ($this->group) { - $loader->setGroups([$this->group]); - } - - // load file - $result = $loader->load($data['CsvFile']['tmp_name']); - - // result message - $msgArr = []; - if ($result->CreatedCount()) { - $msgArr[] = _t( - __CLASS__ . '.ResultCreated', - 'Created {count} members', - ['count' => $result->CreatedCount()] - ); - } - if ($result->UpdatedCount()) { - $msgArr[] = _t( - __CLASS__ . '.ResultUpdated', - 'Updated {count} members', - ['count' => $result->UpdatedCount()] - ); - } - if ($result->DeletedCount()) { - $msgArr[] = _t( - __CLASS__ . '.ResultDeleted', - 'Deleted {count} members', - ['count' => $result->DeletedCount()] - ); - } - $msg = ($msgArr) ? implode(',', $msgArr) : _t(__CLASS__ . '.ResultNone', 'No changes'); - - $this->sessionMessage($msg, 'good'); - - $this->controller->redirectBack(); - } - - /** - * @param $group Group - */ - public function setGroup($group) - { - $this->group = $group; - } - - /** - * @return Group - */ - public function getGroup($group) - { - return $this->group; - } -} diff --git a/code/SecurityAdmin.php b/code/SecurityAdmin.php index e9d3b39f3..8242c7e00 100755 --- a/code/SecurityAdmin.php +++ b/code/SecurityAdmin.php @@ -3,314 +3,145 @@ namespace SilverStripe\Admin; use SilverStripe\CMS\Controllers\CMSMain; -use SilverStripe\Control\HTTPRequest; -use SilverStripe\Control\HTTPResponse; -use SilverStripe\Core\Convert; -use SilverStripe\Core\Injector\Injector; -use SilverStripe\Forms\FieldList; use SilverStripe\Forms\Form; -use SilverStripe\Forms\GridField\GridField; -use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; -use SilverStripe\Forms\GridField\GridFieldDataColumns; -use SilverStripe\Forms\GridField\GridFieldDetailForm; -use SilverStripe\Forms\GridField\GridFieldExportButton; +use SilverStripe\Forms\GridField\GridFieldConfig; use SilverStripe\Forms\GridField\GridFieldImportButton; -use SilverStripe\Forms\GridField\GridFieldPageCount; -use SilverStripe\Forms\HiddenField; use SilverStripe\Forms\LiteralField; -use SilverStripe\Forms\Tab; -use SilverStripe\Forms\TabSet; use SilverStripe\Security\Group; +use SilverStripe\Security\GroupCsvBulkLoader; use SilverStripe\Security\Member; +use SilverStripe\Security\MemberCsvBulkLoader; use SilverStripe\Security\Permission; use SilverStripe\Security\PermissionProvider; use SilverStripe\Security\PermissionRole; -use SilverStripe\View\ArrayData; use SilverStripe\View\Requirements; /** * Security section of the CMS */ -class SecurityAdmin extends LeftAndMain implements PermissionProvider +class SecurityAdmin extends ModelAdmin implements PermissionProvider { - - private static $url_segment = 'security'; - - private static $url_rule = '/$Action/$ID/$OtherID'; - - private static $menu_title = 'Security'; - - private static $tree_class = Group::class; - - private static $subitem_class = Member::class; - - private static $required_permission_codes = 'CMS_ACCESS_SecurityAdmin'; - - private static $menu_icon_class = 'font-icon-torsos-all'; - - private static $allowed_actions = [ - 'EditForm', - 'MemberImportForm', - 'memberimport', - 'GroupImportForm', - 'groupimport', - 'groups', - 'users', - 'roles' + private static $managed_models = [ + 'users' => [ + 'title' => 'Users', + 'dataClass' => Member::class + ], + 'groups' => [ + 'title' => 'Groups', + 'dataClass' => Group::class + ], + 'roles' => [ + 'title' => 'Roles', + 'dataClass' => PermissionRole::class + ], ]; /** - * Shortcut action for setting the correct active tab. - * - * @param HTTPRequest $request - * @return HTTPResponse - */ - public function users($request) - { - return $this->index($request); - } - - /** - * Shortcut action for setting the correct active tab. - * - * @param HTTPRequest $request - * @return HTTPResponse + * We have to add both the model tab reference and the class name as keys for the importers because ModelAdmin + * currently checks for $importers[$modelClass] in some places and $importers[$this->modelTab] in others. + * This is a bug that we should fix in CMS 5 */ - public function groups($request) - { - return $this->index($request); - } + private static $model_importers = [ + 'users' => MemberCsvBulkLoader::class, + Member::class => MemberCsvBulkLoader::class, + 'groups' => GroupCsvBulkLoader::class, + Group::class => GroupCsvBulkLoader::class, + ]; - /** - * Shortcut action for setting the correct active tab. - * - * @param HTTPRequest $request - * @return HTTPResponse - */ - public function roles($request) - { - return $this->index($request); - } + private static $allowed_actions = [ + 'ImportForm', + ]; - public function getEditForm($id = null, $fields = null) - { - // Build gridfield configs - $memberListConfig = GridFieldConfig_RecordEditor::create() - ->addComponent(Injector::inst()->createWithArgs(GridFieldExportButton::class, ['buttons-before-left'])); - $groupListConfig = GridFieldConfig_RecordEditor::create() - ->addComponent(Injector::inst()->createWithArgs(GridFieldExportButton::class, ['buttons-before-left'])); + private static $url_segment = 'security'; - /** @var GridFieldDetailForm $detailForm */ - $detailForm = $memberListConfig->getComponentByType(GridFieldDetailForm::class); - $memberValidator = Member::singleton()->getValidator(); - $detailForm->setValidator($memberValidator); + private static $menu_title = 'Security'; - /** @var GridFieldPageCount $groupPaginator */ - $groupListConfig->removeComponentsByType(GridFieldPageCount::class); - $groupListConfig->addComponent(Injector::inst()->createWithArgs(GridFieldPageCount::class, ['buttons-before-right'])); + private static $menu_priority = 0; - // Add import capabilities. Limit to admin since the import logic can affect assigned permissions - if (Permission::check('ADMIN')) { - // @todo when grid field is converted to react use the react component - $memberListConfig->addComponent( - GridFieldImportButton::create('buttons-before-left') - ->setImportIframe($this->Link('memberimport')) - ->setModalTitle(_t(__CLASS__ . '.IMPORTUSERS', 'Import users')) - ); - $groupListConfig->addComponent( - GridFieldImportButton::create('buttons-before-left') - ->setImportIframe($this->Link('groupimport')) - ->setModalTitle(_t(__CLASS__ . '.IMPORTGROUPS', 'Import groups')) - ); - } + private static $required_permission_codes = 'CMS_ACCESS_SecurityAdmin'; - // Build gridfield - $memberList = GridField::create( - 'Members', - false, - Member::get(), - $memberListConfig - )->addExtraClass("members_grid"); + private static $menu_icon_class = 'font-icon-torsos-all'; - // Build group fields - $groupList = GridField::create( - 'Groups', - false, - Group::get(), - $groupListConfig - ); - /** @var GridFieldDataColumns $columns */ - $columns = $groupList->getConfig()->getComponentByType(GridFieldDataColumns::class); - $columns->setDisplayFields([ - 'Breadcrumbs' => Group::singleton()->fieldLabel('Title') - ]); - $columns->setFieldFormatting([ - 'Breadcrumbs' => function ($val, $item) { - /** @var Group $item */ - return Convert::raw2xml($item->getBreadcrumbs(' > ')); + public function getManagedModels() + { + $models = parent::getManagedModels(); + // Ensure tab titles can be localised + foreach ($models as $key => $spec) { + switch ($spec['dataClass']) { + case Member::class: + $spec['title'] = _t(__CLASS__ . '.Users', 'Users'); + break; + case Group::class: + case PermissionRole::class: + $spec['title'] = singleton($spec['dataClass'])->i18n_plural_name(); } - ]); - - $fields = FieldList::create( - TabSet::create( - 'Root', - Tab::create( - 'Users', - _t(__CLASS__ . '.Users', 'Users'), - LiteralField::create( - 'MembersCautionText', - sprintf( - '', - _t( - __CLASS__ . '.MemberListCaution', - 'Caution: Removing members from this list will remove them from all groups and the database' - ) - ) - ), - $memberList - ), - Tab::create( - 'Groups', - Group::singleton()->i18n_plural_name(), - $groupList - ) - )->setTemplate('SilverStripe\\Forms\\CMSTabSet'), - // necessary for tree node selection in LeftAndMain.EditForm.js - new HiddenField('ID', false, 0) - ); - - // Add roles editing interface - $rolesTab = null; - if (Permission::check('APPLY_ROLES')) { - $rolesField = GridField::create( - 'Roles', - false, - PermissionRole::get(), - GridFieldConfig_RecordEditor::create() - ); - - $rolesTab = $fields->findOrMakeTab('Root.Roles', _t(__CLASS__ . '.TABROLES', 'Roles')); - $rolesTab->push($rolesField); } - - // Build replacement form - $form = Form::create( - $this, - 'EditForm', - $fields, - new FieldList() - )->setHTMLID('Form_EditForm'); - $form->addExtraClass('cms-edit-form fill-height'); - $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); - $form->addExtraClass('ss-tabset cms-tabset ' . $this->BaseCSSClasses()); - $form->setAttribute('data-pjax-fragment', 'CurrentForm'); - - $this->extend('updateEditForm', $form); - - return $form; - } - - public function memberimport() - { - Requirements::clear(); - Requirements::javascript('silverstripe/admin: client/dist/js/vendor.js'); - Requirements::javascript('silverstripe/admin: client/dist/js/MemberImportForm.js'); - Requirements::css('silverstripe/admin: client/dist/styles/bundle.css'); - - return $this->renderWith('BlankPage', [ - 'Form' => $this->MemberImportForm()->forTemplate(), - 'Content' => ' ' - ]); + return $models; } /** - * @see SecurityAdmin_MemberImportForm - * - * @return Form + * @return Form|false */ - public function MemberImportForm() + public function ImportForm() { - if (!Permission::check('ADMIN')) { - return null; + $form = parent::ImportForm(); + if (!$form) { + return $form; } - - /** @var Group $group */ - $group = $this->currentPage(); - $form = new MemberImportForm($this, __FUNCTION__); - $form->setGroup($group); - - return $form; - } - - public function groupimport() - { - Requirements::clear(); - Requirements::javascript('silverstripe/admin: client/dist/js/vendor.js'); - Requirements::javascript('silverstripe/admin: client/dist/js/MemberImportForm.js'); - Requirements::css('silverstripe/admin: client/dist/styles/bundle.css'); - - return $this->renderWith('BlankPage', [ - 'Content' => ' ', - 'Form' => $this->GroupImportForm()->forTemplate() + Requirements::javascript('silverstripe/admin:client/dist/js/MemberImportForm.js'); + $form->Fields()->removeByName('EmptyBeforeImport'); + $name = match ($this->modelClass) { + Member::class => 'SpecForMember', + Group::class => 'SpecForGroup', + }; + $form->Fields()->removeByName($name); + $class = match ($this->modelClass) { + Member::class => MemberCsvBulkLoader::class, + Group::class => GroupCsvBulkLoader::class, + }; + $importSpec = $class::create()->getImportSpec(); + $columns = implode(', ', array_keys($importSpec['fields'] ?? [])); + $helpHtml = implode("\n", [ + _t( + __CLASS__ . '.Help1', + '

Import users in CSV format (comma-separated values).' + . ' Show advanced usage

' + ), + _t( + __CLASS__ . '.Help2', + '
' + . '

Advanced usage

' + . '
    ' + . '
  • Allowed columns: {columns}
  • ' + . '
  • Existing users are matched by their unique Code property, and updated with any new values from ' + . 'the imported file.
  • ' + . '
  • Groups can be assigned by the Groups column. Groups are identified by their Code property, ' + . 'multiple groups can be separated by comma. Existing group memberships are not cleared.
  • ' + . '
' + . '
', + ['columns' => $columns] + ) ]); + $form->Fields()->insertBefore('_CsvFile', LiteralField::create('Help', $helpHtml)); + return $form; } - /** - * @see SecurityAdmin_MemberImportForm - * - * @skipUpgrade - * @return Form - */ - public function GroupImportForm() - { - if (!Permission::check('ADMIN')) { - return null; - } - - return new GroupImportForm($this, __FUNCTION__); - } - - /** - * Disable GridFieldDetailForm backlinks for this view, as its - */ - public function Backlink() - { - return false; - } - - public function Breadcrumbs($unlinked = false) + protected function getGridFieldConfig(): GridFieldConfig { - $crumbs = parent::Breadcrumbs($unlinked); - - // Name root breadcrumb based on which record is edited, - // which can only be determined by looking for the fieldname of the GridField. - // Note: Titles should be same titles as tabs in RootForm(). - $params = $this->getRequest()->allParams(); - if (isset($params['FieldName'])) { - // TODO FieldName param gets overwritten by nested GridFields, - // so shows "Members" rather than "Groups" for the following URL: - // admin/security/EditForm/field/Groups/item/2/ItemEditForm/field/Members/item/1/edit - $firstCrumb = $crumbs->shift(); - if ($params['FieldName'] == 'Groups') { - $crumbs->unshift(new ArrayData([ - 'Title' => Group::singleton()->i18n_plural_name(), - 'Link' => $this->Link('groups') - ])); - } elseif ($params['FieldName'] == 'Users') { - $crumbs->unshift(new ArrayData([ - 'Title' => _t(__CLASS__ . '.Users', 'Users'), - 'Link' => $this->Link('users') - ])); - } elseif ($params['FieldName'] == 'Roles') { - $crumbs->unshift(new ArrayData([ - 'Title' => _t(__CLASS__ . '.TABROLES', 'Roles'), - 'Link' => $this->Link('roles') - ])); - } - $crumbs->unshift($firstCrumb); + $config = parent::getGridFieldConfig(); + // Limit import to admin since the import logic can affect assigned permissions + if (!Permission::check('ADMIN') || $this->modelClass == PermissionRole::class) { + $config->removeComponentsByType(GridFieldImportButton::class); + return $config; } - - return $crumbs; + /** @var GridFieldImportButton $importButton */ + $importButton = $config->getComponentByType(GridFieldImportButton::class); + $modalTitle = match ($this->modelClass) { + Member::class => _t(__CLASS__ . '.IMPORTUSERS', 'Import users'), + Group::class => _t(__CLASS__ . '.IMPORTGROUPS', 'Import groups'), + }; + $importButton->setModalTitle($modalTitle); + return $config; } public function providePermissions() diff --git a/tests/behat/features/manage-users.feature b/tests/behat/features/manage-users.feature index 1cecf226b..08184b3f9 100644 --- a/tests/behat/features/manage-users.feature +++ b/tests/behat/features/manage-users.feature @@ -14,26 +14,25 @@ Feature: Manage users And I am logged in with "ADMIN" permissions And I go to "/admin/security" - Scenario: I cannot remove my admin access, but can remove myself from an admin group When I click the "Groups" CMS tab - And I click "ADMIN group" in the "#Root_Groups" element + And I click "ADMIN group" in the "#Form_EditForm_groups" element And I should see the "Unlink" button in the "Members" gridfield for the "ADMIN" row Then I click "Groups" in the ".breadcrumbs-wrapper" element And I click the "Groups" CMS tab - And I click "ADMIN group2" in the "#Root_Groups" element + And I click "ADMIN group2" in the "#Form_EditForm_groups" element And I should see the "Unlink" button in the "Members" gridfield for the "ADMIN" row Then I click the "Unlink" button in the "Members" gridfield for the "ADMIN" row And I should not see the "Unlink" button in the "Members" gridfield for the "ADMIN" row Then I click "Groups" in the ".breadcrumbs-wrapper" element And I click the "Groups" CMS tab - And I click "ADMIN group" in the "#Root_Groups" element + And I click "ADMIN group" in the "#Form_EditForm_groups" element And I should not see the "Unlink" button in the "Members" gridfield for the "ADMIN" row Scenario: I can list all users regardless of group When I click the "Users" CMS tab - Then I should see "admin@example.org" in the "#Root_Users" element - And I should see "staffmember@example.org" in the "#Root_Users" element + Then I should see "admin@example.org" in the "#Form_EditForm_users" element + And I should see "staffmember@example.org" in the "#Form_EditForm_users" element Scenario: I can search for an existing user by name When I click the "Users" CMS tab @@ -41,8 +40,8 @@ Feature: Manage users And I press the "Advanced" button And I fill in "Search__FirstName" with "ADMIN" And I press the "Enter" key in the "Search__FirstName" field - Then I should see "admin@example.org" in the "#Root_Users" element - But I should not see "staffmember@example.org" in the "#Root_Users" element + Then I should see "admin@example.org" in the "#Form_EditForm_users" element + But I should not see "staffmember@example.org" in the "#Form_EditForm_users" element # Required to avoid "unsaved changes" browser dialog Then I press the "Close" button @@ -52,8 +51,8 @@ Feature: Manage users And I press the "Advanced" button And I fill in "Search__Email" with "staffmember@example.org" And I press the "Search" button - Then I should see "staffmember@example.org" in the "#Root_Users" element - But I should not see "admin@example.org" in the "#Root_Users" element + Then I should see "staffmember@example.org" in the "#Form_EditForm_users" element + But I should not see "admin@example.org" in the "#Form_EditForm_users" element # Required to avoid "unsaved changes" browser dialog Then I press the "Close" button @@ -63,17 +62,17 @@ Feature: Manage users And I press the "Advanced" button And I fill in "Search__Email" with "staffmember@example.org" And I press the "Search" button - And I should see "staffmember@example.org" in the "#Root_Users" element - And I should not see "admin@example.org" in the "#Root_Users" element + And I should see "staffmember@example.org" in the "#Form_EditForm_users" element + And I should not see "admin@example.org" in the "#Form_EditForm_users" element When I press the "Close" button Then I should see a "Open search and filter" button - And I should see "staffmember@example.org" in the "#Root_Users" element - And I should see "admin@example.org" in the "#Root_Users" element + And I should see "staffmember@example.org" in the "#Form_EditForm_users" element + And I should see "admin@example.org" in the "#Form_EditForm_users" element Scenario: I can list all users in a specific group When I click the "Groups" CMS tab # TODO Please check how performant this is - And I click "ADMIN group" in the "#Root_Groups" element + And I click "ADMIN group" in the "#Form_EditForm_groups" element Then I should see "admin@example.org" in the "#Root_Members" element And I should not see "staffmember@example.org" in the "#Root_Members" element @@ -88,18 +87,18 @@ Feature: Manage users Then I should see a "Saved member" message When I go to "admin/security/" - Then I should see "john.doe@example.org" in the "#Root_Users" element + Then I should see "john.doe@example.org" in the "#Form_EditForm_users" element @modal Scenario: I can navigate users from the edit form and retain my search query When I click the "Users" CMS tab And I press the "First Name" button - Then I should see "admin@example.org" in the "#Root_Users" element - And I should see "othermember@example.org" in the "#Root_Users" element - And I should see "staffmember@example.org" in the "#Root_Users" element + Then I should see "admin@example.org" in the "#Form_EditForm_users" element + And I should see "othermember@example.org" in the "#Form_EditForm_users" element + And I should see "staffmember@example.org" in the "#Form_EditForm_users" element - When I click "othermember@example.org" in the "#Root_Users" element + When I click "othermember@example.org" in the "#Form_EditForm_users" element And I follow "Go to next record" Then the "Email" field should contain "staffmember@example.org" @@ -116,19 +115,19 @@ Feature: Manage users Scenario: I can edit an existing user and add him to an existing group When I go to "admin/security/" And I click the "Users" CMS tab - And I click "staffmember@example.org" in the "#Root_Users" element + And I click "staffmember@example.org" in the "#Form_EditForm_users" element And I select "ADMIN group" from "Groups" And I press the "Apply changes|Save" buttons Then I should see a "Saved Member" message When I go to "admin/security" And I click the "Groups" CMS tab - And I click "ADMIN group" in the "#Root_Groups" element + And I click "ADMIN group" in the "#Form_EditForm_groups" element Then I should see "staffmember@example.org" Scenario: I can delete an existing user When I click the "Users" CMS tab - And I click "staffmember@example.org" in the "#Root_Users" element + And I click "staffmember@example.org" in the "#Form_EditForm_users" element And I press the "Delete" button, confirming the dialog Then I should see "admin@example.org" And I should not see "staffmember@example.org" diff --git a/tests/php/SecurityAdminTest.php b/tests/php/SecurityAdminTest.php index 586cbedbf..45ac93b00 100644 --- a/tests/php/SecurityAdminTest.php +++ b/tests/php/SecurityAdminTest.php @@ -55,7 +55,7 @@ public function testPermissionFieldRespectsHiddenPermissions() $group = $this->objFromFixture(Group::class, 'admin'); Config::modify()->merge(Permission::class, 'hidden_permissions', ['CMS_ACCESS_ReportAdmin']); - $response = $this->get(sprintf('admin/security/EditForm/field/Groups/item/%d/edit', $group->ID)); + $response = $this->get(sprintf('/admin/security/groups/EditForm/field/groups/item/%d/edit', $group->ID)); $this->assertStringContainsString( 'CMS_ACCESS_SecurityAdmin',