From ffea501a7210b1ee57a74181d1705b8d99c91e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Tue, 6 Jul 2021 12:16:25 +0200 Subject: [PATCH 1/7] IBX-715: The buttons on the right sidebar are disabled if the user has no permissions --- src/lib/Menu/ContentRightSidebarBuilder.php | 125 +++++++++++++++----- 1 file changed, 97 insertions(+), 28 deletions(-) diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index 205945e110..6b79382549 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -16,6 +16,8 @@ use eZ\Publish\API\Repository\Values\Content\Content; use eZ\Publish\API\Repository\Values\Content\Location; use eZ\Publish\API\Repository\Values\ContentType\ContentType; +use eZ\Publish\API\Repository\Values\User\Limitation\LanguageLimitation; +use eZ\Publish\API\Repository\Values\User\Limitation\SectionLimitation; use eZ\Publish\Core\MVC\ConfigResolverInterface; use eZ\Publish\SPI\Limitation\Target; use eZ\Publish\SPI\Limitation\Target\Builder\VersionBuilder; @@ -177,7 +179,12 @@ public function createStructure(array $options): ItemInterface $location->getContentInfo(), [$location, $target] ); - + $canHide = $this->permissionResolver->canUser( + 'content', + 'hide', + $content, + [$target] + ); $createAttributes = [ 'class' => 'ez-btn--extra-actions ez-btn--create', 'data-actions' => 'create', @@ -194,6 +201,21 @@ public function createStructure(array $options): ItemInterface 'universal_discovery_widget_module.default_location_id' ), ]; + $moveAttributes = [ + 'class' => 'btn--udw-move', + 'data-udw-config' => $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'), + 'data-root-location' => $this->configResolver->getParameter( + 'universal_discovery_widget_module.default_location_id' + ), + ]; + $copyAttributes = [ + 'class' => 'btn--udw-copy', + 'data-udw-config' => $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'), + 'data-root-location' => $this->configResolver->getParameter( + 'universal_discovery_widget_module.default_location_id' + ), + ]; + $canCreateAnywhere = $this->canCreateAnywhere($content); $copyLimit = $this->configResolver->getParameter( 'subtree_operations.copy_subtree.limit' @@ -225,13 +247,9 @@ public function createStructure(array $options): ItemInterface self::ITEM__MOVE, [ 'extras' => ['icon' => 'move'], - 'attributes' => [ - 'class' => 'btn--udw-move', - 'data-udw-config' => $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'), - 'data-root-location' => $this->configResolver->getParameter( - 'universal_discovery_widget_module.default_location_id' - ), - ], + 'attributes' => $canCreateAnywhere + ? $moveAttributes + : array_merge($moveAttributes, ['disabled' => 'disabled']), ] ) ); @@ -241,13 +259,9 @@ public function createStructure(array $options): ItemInterface self::ITEM__COPY, [ 'extras' => ['icon' => 'copy'], - 'attributes' => [ - 'class' => 'btn--udw-copy', - 'data-udw-config' => $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'), - 'data-root-location' => $this->configResolver->getParameter( - 'universal_discovery_widget_module.default_location_id' - ), - ], + 'attributes' => $canCreateAnywhere + ? $copyAttributes + : array_merge($copyAttributes, ['disabled' => 'disabled']), ] ) ); @@ -257,7 +271,7 @@ public function createStructure(array $options): ItemInterface self::ITEM__COPY_SUBTREE, [ 'extras' => ['icon' => 'copy-subtree'], - 'attributes' => $canCopySubtree + 'attributes' => $canCopySubtree && $canCreateAnywhere ? $copySubtreeAttributes : array_merge($copySubtreeAttributes, ['disabled' => 'disabled']), ] @@ -266,9 +280,9 @@ public function createStructure(array $options): ItemInterface } if ($content->getVersionInfo()->getContentInfo()->isHidden) { - $this->addRevealMenuItem($menu); + $this->addRevealMenuItem($menu, $canHide); } else { - $this->addHideMenuItem($menu); + $this->addHideMenuItem($menu, $canHide); } if ($contentIsUser && $canDelete) { @@ -369,17 +383,21 @@ private function addEditMenuItem(ItemInterface $menu, bool $contentIsUser, bool /** * @param \Knp\Menu\ItemInterface $menu */ - private function addRevealMenuItem(ItemInterface $menu): void + private function addRevealMenuItem(ItemInterface $menu, bool $canHide): void { + $attributes = [ + 'data-actions' => 'reveal', + 'class' => 'ez-btn--reveal', + ]; + $menu->addChild( $this->createMenuItem( self::ITEM__REVEAL, [ 'extras' => ['icon' => 'reveal'], - 'attributes' => [ - 'data-actions' => 'reveal', - 'class' => 'ez-btn--reveal', - ], + 'attributes' => $canHide + ? $attributes + : array_merge($attributes, ['disabled' => 'disabled']), ] ) ); @@ -388,19 +406,70 @@ private function addRevealMenuItem(ItemInterface $menu): void /** * @param \Knp\Menu\ItemInterface $menu */ - private function addHideMenuItem(ItemInterface $menu): void + private function addHideMenuItem(ItemInterface $menu, bool $canHide): void { + $attributes = [ + 'data-actions' => 'hide', + 'class' => 'ez-btn--hide', + ]; + $menu->addChild( $this->createMenuItem( self::ITEM__HIDE, [ 'extras' => ['icon' => 'hide'], - 'attributes' => [ - 'data-actions' => 'hide', - 'class' => 'ez-btn--hide', - ], + 'attributes' => $canHide + ? $attributes + : array_merge($attributes, ['disabled' => 'disabled']), ] ) ); } + + private function canCreateAnywhere(Content $content): bool + { + $createPolicies = $this->permissionResolver->hasAccess( + 'content', + 'create' + ); + + if (!$createPolicies) { + return false; + } + + foreach ($createPolicies as $createPolicy) { + $sectionId = $content->contentInfo->sectionId; + if ( + !empty($createPolicy['limitation']) && + $createPolicy['limitation'] instanceof SectionLimitation && + !in_array($sectionId, $createPolicy['limitation']->limitationValues) + ) { + return false; + } + + if (empty($createPolicy['policies'])) { + return true; + } + + foreach ($createPolicy['policies'] as $policy) { + foreach ($policy->limitations as $limitation) { + if ($limitation instanceof SectionLimitation && !in_array($sectionId, $limitation->limitationValues)) { + return false; + } + + if ($limitation instanceof ContentType && !in_array($content->getContentType()->id, $limitation->limitationValues)) { + return false; + } + + $commonArray = \array_intersect($content->getVersionInfo()->languageCodes, $limitation->limitationValues); + + if ($limitation instanceof LanguageLimitation && \count($commonArray) === 0) { + return false; + } + } + } + } + + return true; + } } From 0438ea595a4e03589d1aa65e4ff74c283da5cd3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Wed, 7 Jul 2021 10:23:41 +0200 Subject: [PATCH 2/7] A check has been added if the hasAccess function returned a bool --- src/lib/Menu/ContentRightSidebarBuilder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index 6b79382549..7fcccab860 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -433,8 +433,8 @@ private function canCreateAnywhere(Content $content): bool 'create' ); - if (!$createPolicies) { - return false; + if (is_bool($createPolicies)) { + return $createPolicies; } foreach ($createPolicies as $createPolicy) { From 4f9047ed51562f15645d42a1f59ccc05898a482f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Tue, 13 Jul 2021 12:05:34 +0200 Subject: [PATCH 3/7] removed unused private variables and used ContentTypeLimitation, corrected CS --- src/lib/Menu/ContentRightSidebarBuilder.php | 27 ++++----------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index 7fcccab860..d7d16e4480 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -8,14 +8,12 @@ namespace EzSystems\EzPlatformAdminUi\Menu; -use eZ\Publish\API\Repository\ContentService; -use eZ\Publish\API\Repository\ContentTypeService; -use eZ\Publish\API\Repository\LocationService; use eZ\Publish\API\Repository\PermissionResolver; use eZ\Publish\API\Repository\SearchService; use eZ\Publish\API\Repository\Values\Content\Content; use eZ\Publish\API\Repository\Values\Content\Location; use eZ\Publish\API\Repository\Values\ContentType\ContentType; +use eZ\Publish\API\Repository\Values\User\Limitation\ContentTypeLimitation; use eZ\Publish\API\Repository\Values\User\Limitation\LanguageLimitation; use eZ\Publish\API\Repository\Values\User\Limitation\SectionLimitation; use eZ\Publish\Core\MVC\ConfigResolverInterface; @@ -57,21 +55,12 @@ class ContentRightSidebarBuilder extends AbstractBuilder implements TranslationC /** @var \eZ\Publish\Core\MVC\ConfigResolverInterface */ private $configResolver; - /** @var \eZ\Publish\API\Repository\ContentTypeService */ - private $contentTypeService; - /** @var \eZ\Publish\API\Repository\SearchService */ private $searchService; /** @var \EzSystems\EzPlatformAdminUiBundle\Templating\Twig\UniversalDiscoveryExtension */ private $udwExtension; - /** @var \eZ\Publish\API\Repository\ContentService */ - private $contentService; - - /** @var \eZ\Publish\API\Repository\LocationService */ - private $locationService; - /** @var \EzSystems\EzPlatformAdminUi\Permission\PermissionCheckerInterface */ private $permissionChecker; @@ -100,11 +89,8 @@ public function __construct( EventDispatcherInterface $eventDispatcher, PermissionResolver $permissionResolver, ConfigResolverInterface $configResolver, - ContentTypeService $contentTypeService, SearchService $searchService, UniversalDiscoveryExtension $udwExtension, - ContentService $contentService, - LocationService $locationService, PermissionCheckerInterface $permissionChecker, array $userContentTypeIdentifier, array $userGroupContentTypeIdentifier @@ -113,11 +99,8 @@ public function __construct( $this->permissionResolver = $permissionResolver; $this->configResolver = $configResolver; - $this->contentTypeService = $contentTypeService; $this->searchService = $searchService; $this->udwExtension = $udwExtension; - $this->contentService = $contentService; - $this->locationService = $locationService; $this->permissionChecker = $permissionChecker; $this->userContentTypeIdentifier = $userContentTypeIdentifier; $this->userGroupContentTypeIdentifier = $userGroupContentTypeIdentifier; @@ -440,9 +423,9 @@ private function canCreateAnywhere(Content $content): bool foreach ($createPolicies as $createPolicy) { $sectionId = $content->contentInfo->sectionId; if ( - !empty($createPolicy['limitation']) && - $createPolicy['limitation'] instanceof SectionLimitation && - !in_array($sectionId, $createPolicy['limitation']->limitationValues) + !empty($createPolicy['limitation']) + && $createPolicy['limitation'] instanceof SectionLimitation + && !in_array($sectionId, $createPolicy['limitation']->limitationValues) ) { return false; } @@ -457,7 +440,7 @@ private function canCreateAnywhere(Content $content): bool return false; } - if ($limitation instanceof ContentType && !in_array($content->getContentType()->id, $limitation->limitationValues)) { + if ($limitation instanceof ContentTypeLimitation && !in_array($content->getContentType()->id, $limitation->limitationValues)) { return false; } From fd08c74a66e23b061135baf6a2f9b786bbb5bd39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Tue, 13 Jul 2021 12:13:33 +0200 Subject: [PATCH 4/7] set $createPolicy['policies'] as default on empty array --- src/lib/Menu/ContentRightSidebarBuilder.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index d7d16e4480..7bebf020c4 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -430,11 +430,7 @@ private function canCreateAnywhere(Content $content): bool return false; } - if (empty($createPolicy['policies'])) { - return true; - } - - foreach ($createPolicy['policies'] as $policy) { + foreach ($createPolicy['policies'] ?? [] as $policy) { foreach ($policy->limitations as $limitation) { if ($limitation instanceof SectionLimitation && !in_array($sectionId, $limitation->limitationValues)) { return false; From e9e4d0fe7a6bcb02be2274d5bc25e5c0da299db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Fri, 6 Aug 2021 16:14:14 +0200 Subject: [PATCH 5/7] changed conception to verify permission to actions --- src/lib/Menu/ContentRightSidebarBuilder.php | 63 +++++---------------- 1 file changed, 13 insertions(+), 50 deletions(-) diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index 7bebf020c4..f68eab5c2c 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -13,9 +13,6 @@ use eZ\Publish\API\Repository\Values\Content\Content; use eZ\Publish\API\Repository\Values\Content\Location; use eZ\Publish\API\Repository\Values\ContentType\ContentType; -use eZ\Publish\API\Repository\Values\User\Limitation\ContentTypeLimitation; -use eZ\Publish\API\Repository\Values\User\Limitation\LanguageLimitation; -use eZ\Publish\API\Repository\Values\User\Limitation\SectionLimitation; use eZ\Publish\Core\MVC\ConfigResolverInterface; use eZ\Publish\SPI\Limitation\Target; use eZ\Publish\SPI\Limitation\Target\Builder\VersionBuilder; @@ -198,7 +195,16 @@ public function createStructure(array $options): ItemInterface 'universal_discovery_widget_module.default_location_id' ), ]; - $canCreateAnywhere = $this->canCreateAnywhere($content); + $createPolicies = $this->permissionResolver->hasAccess( + 'content', + 'create' + ); + $manageLocationsPolicies = $this->permissionResolver->hasAccess( + 'content', + 'manage_locations' + ); + $hasCreatePermission = is_bool($createPolicies) ? $createPolicies : true; + $hasManageLocationsPermission = is_bool($manageLocationsPolicies) ? $manageLocationsPolicies : true; $copyLimit = $this->configResolver->getParameter( 'subtree_operations.copy_subtree.limit' @@ -230,7 +236,7 @@ public function createStructure(array $options): ItemInterface self::ITEM__MOVE, [ 'extras' => ['icon' => 'move'], - 'attributes' => $canCreateAnywhere + 'attributes' => $hasCreatePermission ? $moveAttributes : array_merge($moveAttributes, ['disabled' => 'disabled']), ] @@ -242,7 +248,7 @@ public function createStructure(array $options): ItemInterface self::ITEM__COPY, [ 'extras' => ['icon' => 'copy'], - 'attributes' => $canCreateAnywhere + 'attributes' => $hasCreatePermission && $hasManageLocationsPermission ? $copyAttributes : array_merge($copyAttributes, ['disabled' => 'disabled']), ] @@ -254,7 +260,7 @@ public function createStructure(array $options): ItemInterface self::ITEM__COPY_SUBTREE, [ 'extras' => ['icon' => 'copy-subtree'], - 'attributes' => $canCopySubtree && $canCreateAnywhere + 'attributes' => $canCopySubtree && $hasCreatePermission ? $copySubtreeAttributes : array_merge($copySubtreeAttributes, ['disabled' => 'disabled']), ] @@ -408,47 +414,4 @@ private function addHideMenuItem(ItemInterface $menu, bool $canHide): void ) ); } - - private function canCreateAnywhere(Content $content): bool - { - $createPolicies = $this->permissionResolver->hasAccess( - 'content', - 'create' - ); - - if (is_bool($createPolicies)) { - return $createPolicies; - } - - foreach ($createPolicies as $createPolicy) { - $sectionId = $content->contentInfo->sectionId; - if ( - !empty($createPolicy['limitation']) - && $createPolicy['limitation'] instanceof SectionLimitation - && !in_array($sectionId, $createPolicy['limitation']->limitationValues) - ) { - return false; - } - - foreach ($createPolicy['policies'] ?? [] as $policy) { - foreach ($policy->limitations as $limitation) { - if ($limitation instanceof SectionLimitation && !in_array($sectionId, $limitation->limitationValues)) { - return false; - } - - if ($limitation instanceof ContentTypeLimitation && !in_array($content->getContentType()->id, $limitation->limitationValues)) { - return false; - } - - $commonArray = \array_intersect($content->getVersionInfo()->languageCodes, $limitation->limitationValues); - - if ($limitation instanceof LanguageLimitation && \count($commonArray) === 0) { - return false; - } - } - } - } - - return true; - } } From f935db7e915137052285cc33e6e3998d2c1b7b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Thu, 19 Aug 2021 17:09:46 +0200 Subject: [PATCH 6/7] moved UWD.default_location_id and uwd config to variables --- src/lib/Menu/ContentRightSidebarBuilder.php | 24 +++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index f68eab5c2c..f27ef657ec 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -135,6 +135,8 @@ public function createStructure(array $options): ItemInterface $lookupLimitationsResult = $this->permissionChecker->getContentCreateLimitations($location); $canCreate = $lookupLimitationsResult->hasAccess && $contentType->isContainer; + $rootLocation = $this->configResolver->getParameter('universal_discovery_widget_module.default_location_id'); + $uwdConfig = $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'); $canEdit = $this->permissionResolver->canUser( 'content', 'edit', @@ -176,24 +178,18 @@ public function createStructure(array $options): ItemInterface ]; $copySubtreeAttributes = [ 'class' => 'ez-btn--udw-copy-subtree', - 'data-udw-config' => $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'), - 'data-root-location' => $this->configResolver->getParameter( - 'universal_discovery_widget_module.default_location_id' - ), + 'data-udw-config' => $uwdConfig, + 'data-root-location' => $rootLocation, ]; $moveAttributes = [ 'class' => 'btn--udw-move', - 'data-udw-config' => $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'), - 'data-root-location' => $this->configResolver->getParameter( - 'universal_discovery_widget_module.default_location_id' - ), + 'data-udw-config' => $uwdConfig, + 'data-root-location' => $rootLocation, ]; $copyAttributes = [ 'class' => 'btn--udw-copy', - 'data-udw-config' => $this->udwExtension->renderUniversalDiscoveryWidgetConfig('single_container'), - 'data-root-location' => $this->configResolver->getParameter( - 'universal_discovery_widget_module.default_location_id' - ), + 'data-udw-config' => $uwdConfig, + 'data-root-location' => $rootLocation, ]; $createPolicies = $this->permissionResolver->hasAccess( 'content', @@ -203,8 +199,8 @@ public function createStructure(array $options): ItemInterface 'content', 'manage_locations' ); - $hasCreatePermission = is_bool($createPolicies) ? $createPolicies : true; - $hasManageLocationsPermission = is_bool($manageLocationsPolicies) ? $manageLocationsPolicies : true; + $hasCreatePermission = !is_bool($createPolicies) || $createPolicies; + $hasManageLocationsPermission = !is_bool($manageLocationsPolicies) || $manageLocationsPolicies; $copyLimit = $this->configResolver->getParameter( 'subtree_operations.copy_subtree.limit' From ead7610760e6067a7ffba258bf7bebd0bfd63a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Mon, 23 Aug 2021 13:02:59 +0200 Subject: [PATCH 7/7] logic has been extracted into separate functions --- src/lib/Menu/ContentRightSidebarBuilder.php | 61 ++++++++++++++------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index f27ef657ec..70a1d5860f 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -167,6 +167,9 @@ public function createStructure(array $options): ItemInterface $content, [$target] ); + $hasCreatePermission = $this->hasCreatePermission(); + $canCopy = $this->canCopy($hasCreatePermission); + $canCopySubtree = $this->canCopySubtree($location, $hasCreatePermission); $createAttributes = [ 'class' => 'ez-btn--extra-actions ez-btn--create', 'data-actions' => 'create', @@ -191,24 +194,6 @@ public function createStructure(array $options): ItemInterface 'data-udw-config' => $uwdConfig, 'data-root-location' => $rootLocation, ]; - $createPolicies = $this->permissionResolver->hasAccess( - 'content', - 'create' - ); - $manageLocationsPolicies = $this->permissionResolver->hasAccess( - 'content', - 'manage_locations' - ); - $hasCreatePermission = !is_bool($createPolicies) || $createPolicies; - $hasManageLocationsPermission = !is_bool($manageLocationsPolicies) || $manageLocationsPolicies; - - $copyLimit = $this->configResolver->getParameter( - 'subtree_operations.copy_subtree.limit' - ); - $canCopySubtree = (new IsWithinCopySubtreeLimit( - $copyLimit, - $this->searchService - ))->and((new IsRoot())->not())->isSatisfiedBy($location); $contentIsUser = (new ContentTypeIsUser($this->userContentTypeIdentifier))->isSatisfiedBy($contentType); $contentIsUserGroup = (new ContentTypeIsUserGroup($this->userGroupContentTypeIdentifier))->isSatisfiedBy($contentType); @@ -244,7 +229,7 @@ public function createStructure(array $options): ItemInterface self::ITEM__COPY, [ 'extras' => ['icon' => 'copy'], - 'attributes' => $hasCreatePermission && $hasManageLocationsPermission + 'attributes' => $canCopy ? $copyAttributes : array_merge($copyAttributes, ['disabled' => 'disabled']), ] @@ -256,7 +241,7 @@ public function createStructure(array $options): ItemInterface self::ITEM__COPY_SUBTREE, [ 'extras' => ['icon' => 'copy-subtree'], - 'attributes' => $canCopySubtree && $hasCreatePermission + 'attributes' => $canCopySubtree ? $copySubtreeAttributes : array_merge($copySubtreeAttributes, ['disabled' => 'disabled']), ] @@ -410,4 +395,40 @@ private function addHideMenuItem(ItemInterface $menu, bool $canHide): void ) ); } + + private function hasCreatePermission(): bool + { + $createPolicies = $this->permissionResolver->hasAccess( + 'content', + 'create' + ); + + return !is_bool($createPolicies) || $createPolicies; + } + + private function canCopy(bool $hasCreatePermission): bool + { + $manageLocationsPolicies = $this->permissionResolver->hasAccess( + 'content', + 'manage_locations' + ); + + $hasManageLocationsPermission = !is_bool($manageLocationsPolicies) || $manageLocationsPolicies; + + return $hasCreatePermission && $hasManageLocationsPermission; + } + + private function canCopySubtree(Location $location, bool $hasCreatePermission): bool + { + $copyLimit = $this->configResolver->getParameter( + 'subtree_operations.copy_subtree.limit' + ); + + $canCopySubtree = (new IsWithinCopySubtreeLimit( + $copyLimit, + $this->searchService + ))->and((new IsRoot())->not())->isSatisfiedBy($location); + + return $canCopySubtree && $hasCreatePermission; + } }