diff --git a/code/SiteConfig.php b/code/SiteConfig.php index 70f669a55..87ea4bddc 100644 --- a/code/SiteConfig.php +++ b/code/SiteConfig.php @@ -22,6 +22,7 @@ use SilverStripe\Security\Security; use SilverStripe\View\TemplateGlobalProvider; use SilverStripe\CMS\Controllers\CMSMain; +use SilverStripe\Security\InheritedPermissions; /** * SiteConfig @@ -40,15 +41,18 @@ class SiteConfig extends DataObject implements PermissionProvider, TemplateGloba private static $db = [ "Title" => "Varchar(255)", "Tagline" => "Varchar(255)", - "CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')", - "CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')", - "CanCreateTopLevelType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')", + "CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers, OnlyTheseMembers', 'Anyone')", + "CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers, OnlyTheseMembers', 'LoggedInUsers')", + "CanCreateTopLevelType" => "Enum('LoggedInUsers, OnlyTheseUsers, OnlyTheseMembers', 'LoggedInUsers')", ]; private static $many_many = [ "ViewerGroups" => Group::class, "EditorGroups" => Group::class, "CreateTopLevelGroups" => Group::class, + "ViewerMembers" => Member::class, + "EditorMembers" => Member::class, + "CreateTopLevelMembers" => Member::class, ]; private static $defaults = [ @@ -100,6 +104,7 @@ public function getCMSFields() $groupsMap = $mapFn(Group::get()); $viewAllGroupsMap = $mapFn(Permission::get_groups_by_permission(['SITETREE_VIEW_ALL', 'ADMIN'])); $editAllGroupsMap = $mapFn(Permission::get_groups_by_permission(['SITETREE_EDIT_ALL', 'ADMIN'])); + $membersMap = Member::get()->map('ID', 'Name'); $fields = FieldList::create( TabSet::create( @@ -127,6 +132,11 @@ public function getCMSFields() 'data-placeholder', _t('SilverStripe\\CMS\\Model\\SiteTree.GroupPlaceholder', 'Click to select group') ), + $viewerMembersField = ListboxField::create( + "ViewerMembers", + _t(self::class . '.VIEWERMEMBERS', "Viewer Users"), + $membersMap, + ), $editorsOptionsField = OptionsetField::create( "CanEditType", _t(self::class . '.EDITHEADER', "Who can edit pages on this site?") @@ -140,19 +150,29 @@ public function getCMSFields() 'data-placeholder', _t('SilverStripe\\CMS\\Model\\SiteTree.GroupPlaceholder', 'Click to select group') ), + $editorMembersField = ListboxField::create( + "EditorMembers", + _t(self::class . '.EDITORMEMBERS', "Editor Users"), + $membersMap, + ), $topLevelCreatorsOptionsField = OptionsetField::create( "CanCreateTopLevelType", _t(self::class . '.TOPLEVELCREATE', "Who can create pages in the root of the site?") ), $topLevelCreatorsGroupsField = ListboxField::create( "CreateTopLevelGroups", - _t(self::class . '.TOPLEVELCREATORGROUPS', "Top level creators") + _t(self::class . '.TOPLEVELCREATORGROUPS2', "Top level creator groups") ) ->setSource($groupsMap) ->setAttribute( 'data-placeholder', _t('SilverStripe\\CMS\\Model\\SiteTree.GroupPlaceholder', 'Click to select group') - ) + ), + $topLevelCreatorsMembersField = ListboxField::create( + "CreateTopLevelMembers", + _t(self::class . '.TOPLEVELCREATORUSERS', "Top level creator users"), + $membersMap, + ) ) ), HiddenField::create('ID') @@ -168,6 +188,10 @@ public function getCMSFields() 'SilverStripe\\CMS\\Model\\SiteTree.ACCESSONLYTHESE', "Only these groups (choose from list)" ); + $viewersOptionsSource[InheritedPermissions::ONLY_THESE_MEMBERS] = _t( + self::class . '.ACCESSONLYTHESEMEMBERS', + "Only these users (choose from list)" + ); $viewersOptionsField->setSource($viewersOptionsSource); if ($viewAllGroupsMap) { @@ -195,19 +219,53 @@ public function getCMSFields() 'SilverStripe\\CMS\\Model\\SiteTree.EDITONLYTHESE', "Only these groups (choose from list)" ); + $editorsOptionsSource[InheritedPermissions::ONLY_THESE_MEMBERS] = _t( + self::class . '.EDITONLYTHESEMEMBERS', + "Only these users (choose from list)" + ); $editorsOptionsField->setSource($editorsOptionsSource); $topLevelCreatorsOptionsField->setSource($editorsOptionsSource); if (!Permission::check('EDIT_SITECONFIG')) { + $fields->makeFieldReadonly($taglineField); + $fields->makeFieldReadonly($titleField); + // Hide and remove appropriate viewer fields $fields->makeFieldReadonly($viewersOptionsField); - $fields->makeFieldReadonly($viewerGroupsField); + if ($this->CanViewType === InheritedPermissions::ONLY_THESE_USERS) { + $fields->makeFieldReadonly($viewerGroupsField); + $fields->removeByName('ViewerMembers'); + } elseif ($this->CanViewType === InheritedPermissions::ONLY_THESE_MEMBERS) { + $fields->makeFieldReadonly($viewerMembersField); + $fields->removeByName('ViewerGroups'); + } else { + $fields->removeByName('ViewerGroups'); + $fields->removeByName('ViewerMembers'); + } + // Hide and remove appropriate editor fields $fields->makeFieldReadonly($editorsOptionsField); - $fields->makeFieldReadonly($editorGroupsField); + if ($this->CanEditType === InheritedPermissions::ONLY_THESE_USERS) { + $fields->makeFieldReadonly($editorGroupsField); + $fields->removeByName('EditorMembers'); + } elseif ($this->CanEditType === InheritedPermissions::ONLY_THESE_MEMBERS) { + $fields->makeFieldReadonly($editorMembersField); + $fields->removeByName('EditorGroups'); + } else { + $fields->removeByName('EditorGroups'); + $fields->removeByName('EditorMembers'); + } + // Hide and remove appropriate top-level creator fields $fields->makeFieldReadonly($topLevelCreatorsOptionsField); - $fields->makeFieldReadonly($topLevelCreatorsGroupsField); - $fields->makeFieldReadonly($taglineField); - $fields->makeFieldReadonly($titleField); + if ($this->CanCreateTopLevelType === InheritedPermissions::ONLY_THESE_USERS) { + $fields->makeFieldReadonly($topLevelCreatorsGroupsField); + $fields->removeByName('CreateTopLevelMembers'); + } elseif ($this->CanCreateTopLevelType === InheritedPermissions::ONLY_THESE_MEMBERS) { + $fields->makeFieldReadonly($topLevelCreatorsMembersField); + $fields->removeByName('CreateTopLevelGroups'); + } else { + $fields->removeByName('CreateTopLevelGroups'); + $fields->removeByName('CreateTopLevelMembers'); + } } if (file_exists(BASE_PATH . '/install.php')) { @@ -370,6 +428,14 @@ public function canViewPages($member = null) return true; } + // check for specific users + if ($this->CanViewType === InheritedPermissions::ONLY_THESE_MEMBERS + && $member + && $this->ViewerMembers()->filter('ID', $member->ID)->count() > 0 + ) { + return true; + } + return false; } @@ -403,11 +469,19 @@ public function canEditPages($member = null) return true; } - // check for specific groups + // check for specific groups if ($this->CanEditType === 'OnlyTheseUsers' && $member && $member->inGroups($this->EditorGroups())) { return true; } + // check for specific users + if ($this->CanEditType === InheritedPermissions::ONLY_THESE_MEMBERS + && $member + && $this->EditorMembers()->filter('ID', $member->ID)->count() > 0 + ) { + return true; + } + return false; } @@ -482,6 +556,14 @@ public function canCreateTopLevel($member = null) return true; } + // check for specific users + if ($this->CanCreateTopLevelType === InheritedPermissions::ONLY_THESE_MEMBERS + && $member + && $this->CreateTopLevelMembers()->filter('ID', $member->ID)->count() > 0 + ) { + return true; + } + return false; } diff --git a/tests/behat/features/manage-page-permissions.feature b/tests/behat/features/manage-page-permissions.feature index 5973bd065..f342740c7 100644 --- a/tests/behat/features/manage-page-permissions.feature +++ b/tests/behat/features/manage-page-permissions.feature @@ -7,6 +7,9 @@ Feature: Manage global page permissions Given a "page" "Home" with "Content"="

Welcome

" And a "group" "AUTHOR" has permissions "Access to 'Pages' section" And a "group" "SECURITY" has permissions "Access to 'Security' section" + # Have to supply an email address like this for "I am logged in as a member of group" to find this user + And a "member" "AUTHOR" belonging to "AUTHOR" with "Email"="AUTHOR@example.org" + And a "member" "SECURITY" belonging to "SECURITY" with "Email"="SECURITY@example.org" And I am logged in with "ADMIN" permissions And I go to "admin/settings" And I click the "Access" CMS tab @@ -43,6 +46,28 @@ Feature: Manage global page permissions And I go to the homepage Then I should see "Welcome" + Scenario: I can limit global view permissions to certain members + Given I select "Only these users (choose from list)" from "Who can view pages on this site?" input group + And I select "AUTHOR" from "Viewer Users" with javascript + And I press the "Save" button + When I am not logged in + And I go to the homepage + Then I should see a log-in form + When I am logged in as a member of "SECURITY" group + And I go to the homepage + Then I will see a "warning" log-in message + When I am not logged in + And I am logged in as a member of "AUTHOR" group + And I go to the homepage + Then I should see "Welcome" + + Scenario: I can open global edit permissions to everyone + Given I select "Anyone who can log-in to the CMS" from "Who can edit pages on this site?" input group + And I press the "Save" button + Then pages should be editable by "AUTHOR" + # "anyone" doesn't override actual permissions + And pages should not be editable by "SECURITY" + Scenario: I can limit global edit permissions to logged-in users Given I am not logged in And I am logged in as a member of "AUTHOR" group @@ -55,11 +80,95 @@ Feature: Manage global page permissions And I press the "Save" button Then pages should be editable by "AUTHOR" And pages should be editable by "ADMIN" + And pages should not be editable by "SECURITY" Scenario: I can limit global edit permissions to certain groups - Given I select "Only these groups (choose from list)" from "Who can edit pages on this site?" input group + When I select "Only these groups (choose from list)" from "Who can edit pages on this site?" input group And I select "ADMIN group" from "Editor Groups" with javascript And I press the "Save" button Then pages should not be editable by "AUTHOR" + And pages should not be editable by "SECURITY" + But pages should be editable by "ADMIN" + + Scenario: I can limit global edit permissions to certain members + Given I select "Only these users (choose from list)" from "Who can edit pages on this site?" input group + And I select "ADMIN" from "Editor Users" with javascript + And I press the "Save" button + Then pages should not be editable by "AUTHOR" + And pages should not be editable by "SECURITY" But pages should be editable by "ADMIN" + Scenario: I should only see member/group fields when I am limiting access to members/groups (View) + Given I select "Anyone" from "Who can view pages on this site?" input group + # Need to wait a beat after each selection so the animation has time to finish + And I wait for 1 second + Then I should not see "Viewer Groups" + And I should not see "Viewer Users" + When I select "Logged-in users" from "Who can view pages on this site?" input group + And I wait for 1 second + Then I should not see "Viewer Groups" + And I should not see "Viewer Users" + When I select "Only these groups (choose from list)" from "Who can view pages on this site?" input group + And I wait for 1 second + Then I should see "Viewer Groups" + And I should not see "Viewer Users" + When I select "Only these users (choose from list)" from "Who can view pages on this site?" input group + And I wait for 1 second + Then I should not see "Viewer Groups" + And I should see "Viewer Users" + When I select "Logged-in users" from "Who can view pages on this site?" input group + And I wait for 1 second + Then I should not see "Viewer Groups" + And I should not see "Viewer Users" + # Avoids having a toast which crashes the test + When I press the "Save" button + + Scenario: I should only see member/group fields when I am limiting access to members/groups (Edit) + Given I select "Anyone who can log-in to the CMS" from "Who can edit pages on this site?" input group + # Need to wait a beat after each selection so the animation has time to finish + And I wait for 1 second + Then I should not see "Editor Groups" + And I should not see "Editor Users" + When I select "Logged-in users" from "Who can edit pages on this site?" input group + And I wait for 1 second + Then I should not see "Editor Groups" + And I should not see "Editor Users" + When I select "Only these groups (choose from list)" from "Who can edit pages on this site?" input group + And I wait for 1 second + Then I should see "Editor Groups" + And I should not see "Editor Users" + When I select "Only these users (choose from list)" from "Who can edit pages on this site?" input group + And I wait for 1 second + Then I should not see "Editor Groups" + And I should see "Editor Users" + When I select "Anyone who can log-in to the CMS" from "Who can edit pages on this site?" input group + And I wait for 1 second + Then I should not see "Editor Groups" + And I should not see "Editor Users" + # Avoids having a toast which crashes the test + When I press the "Save" button + + Scenario: I should only see member/group fields when I am limiting access to members/groups (Create) + Given I select "Anyone who can log-in to the CMS" from "Who can create pages in the root of the site?" input group + # Need to wait a beat after each selection so the animation has time to finish + And I wait for 1 second + Then I should not see "Top level creator groups" + And I should not see "Top level creator users" + When I select "Logged-in users" from "Who can create pages in the root of the site?" input group + And I wait for 1 second + Then I should not see "Top level creator groups" + And I should not see "Top level creator users" + When I select "Only these groups (choose from list)" from "Who can create pages in the root of the site?" input group + And I wait for 1 second + Then I should see "Top level creator groups" + And I should not see "Top level creator users" + When I select "Only these users (choose from list)" from "Who can create pages in the root of the site?" input group + And I wait for 1 second + Then I should not see "Top level creator groups" + And I should see "Top level creator users" + When I select "Anyone who can log-in to the CMS" from "Who can create pages in the root of the site?" input group + And I wait for 1 second + Then I should not see "Top level creator groups" + And I should not see "Top level creator users" + # Avoids having a toast which crashes the test + When I press the "Save" button