diff --git a/eZ/Publish/API/Repository/Tests/Limitation/PermissionResolver/LocationLimitationIntegrationTest.php b/eZ/Publish/API/Repository/Tests/Limitation/PermissionResolver/LocationLimitationIntegrationTest.php new file mode 100644 index 00000000000..2ce01c4399b --- /dev/null +++ b/eZ/Publish/API/Repository/Tests/Limitation/PermissionResolver/LocationLimitationIntegrationTest.php @@ -0,0 +1,65 @@ +limitationValues = [self::LOCATION_ID]; + + return [ + [[$limitationRoot], true], + ]; + } + + /** + * @dataProvider providerForCanUserEditOrPublishContent + * + * @param array $limitations + * @param bool $expectedResult + * + * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException + * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException + * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException + */ + public function testCanUserEditContent(array $limitations, bool $expectedResult): void + { + $repository = $this->getRepository(); + $locationService = $repository->getLocationService(); + + $location = $locationService->loadLocation(2); + + $this->loginAsEditorUserWithLimitations('content', 'edit', $limitations); + + $this->assertCanUser( + $expectedResult, + 'content', + 'edit', + $limitations, + $location->contentInfo, + [$location] + ); + + $this->assertCanUser( + $expectedResult, + 'content', + 'edit', + $limitations, + $location->contentInfo, + [$location, new Version(['allLanguageCodesList' => 'eng-GB'])] + ); + } +} diff --git a/eZ/Publish/API/Repository/Tests/PermissionResolverTest.php b/eZ/Publish/API/Repository/Tests/PermissionResolverTest.php index 6fd213f83a4..bb66a90a227 100644 --- a/eZ/Publish/API/Repository/Tests/PermissionResolverTest.php +++ b/eZ/Publish/API/Repository/Tests/PermissionResolverTest.php @@ -6,6 +6,7 @@ */ namespace eZ\Publish\API\Repository\Tests; +use eZ\Publish\SPI\Limitation\Target\Builder\VersionBuilder; use function array_filter; use eZ\Publish\API\Repository\Repository; use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct; @@ -1238,6 +1239,73 @@ public function testLookupLimitationsWithRoleLimitationsHasNoAccess(): void ); } + public function testLookupLimitationsWithMixedTargets(): void + { + $repository = $this->getRepository(); + $userService = $repository->getUserService(); + $permissionResolver = $repository->getPermissionResolver(); + $roleService = $repository->getRoleService(); + $locationService = $repository->getLocationService(); + + $location = $locationService->loadLocation(2); + $module = 'content'; + $function = 'edit'; + + $role = $this->createRoleWithPolicies( + 'role_' . __FUNCTION__, + [ + [ + 'module' => $module, + 'function' => $function, + 'limitations' => [ + new Limitation\LocationLimitation(['limitationValues' => [$location->id]]), + ], + ], + [ + 'module' => $module, + 'function' => $function, + 'limitations' => [ + new Limitation\LanguageLimitation(['limitationValues' => ['eng-GB']]), + ], + ], + ] + ); + $user = $this->createUser('user', 'John', 'Doe', $userService->loadUserGroup(4)); + $roleService->assignRoleToUser($role, $user); + $permissionResolver->setCurrentUserReference($user); + + $expected = new LookupLimitationResult( + true, + [], + [ + new LookupPolicyLimitations( + $role->getPolicies()[0], + [] + ), + new LookupPolicyLimitations( + $role->getPolicies()[1], + [ + new Limitation\LanguageLimitation(['limitationValues' => ['eng-GB']]), + ] + ), + ] + ); + + self::assertEquals( + $expected, + $permissionResolver->lookupLimitations( + $module, + $function, + $location->contentInfo, + [ + (new VersionBuilder())->translateToAnyLanguageOf(['eng-GB'])->build(), + $location, + ], + [Limitation::LANGUAGE] + ) + ); + } + /** * @param \eZ\Publish\API\Repository\Repository $repository * @param string $contentTypeIdentifier diff --git a/eZ/Publish/Core/Limitation/LocationLimitationType.php b/eZ/Publish/Core/Limitation/LocationLimitationType.php index f86fb408186..520bfdff502 100644 --- a/eZ/Publish/Core/Limitation/LocationLimitationType.php +++ b/eZ/Publish/Core/Limitation/LocationLimitationType.php @@ -138,19 +138,22 @@ public function evaluate(APILimitationValue $value, APIUserReference $currentUse $targets = $this->persistence->locationHandler()->loadParentLocationsForDraftContent($object->id); } } + /** @var \eZ\Publish\API\Repository\Values\Content\Location[]|\eZ\Publish\SPI\Persistence\Content\Location[] $targets */ + $targets = array_filter($targets, function ($target) { + return $target instanceof Location || $target instanceof SPILocation; + }); - foreach ($targets as $target) { - if (!$target instanceof Location && !$target instanceof SPILocation) { - throw new InvalidArgumentException('$targets', 'Must contain objects of type: Location'); - } + if (empty($targets)) { + throw new InvalidArgumentException('$targets', 'Must contain at least one Location object'); + } - // Single match is sufficient + foreach ($targets as $target) { if (in_array($target->id, $value->limitationValues)) { - return true; + return self::ACCESS_GRANTED; } } - return false; + return self::ACCESS_DENIED; } /** diff --git a/eZ/Publish/Core/Repository/Permission/PermissionResolver.php b/eZ/Publish/Core/Repository/Permission/PermissionResolver.php index ec8bea73432..697234dbc91 100644 --- a/eZ/Publish/Core/Repository/Permission/PermissionResolver.php +++ b/eZ/Publish/Core/Repository/Permission/PermissionResolver.php @@ -339,7 +339,12 @@ private function isGrantedByLimitation( ?array $targets ): bool { $type = $this->limitationService->getLimitationType($limitation->getIdentifier()); - $accessVote = $type->evaluate($limitation, $currentUserReference, $object, $targets); + $accessVote = $type->evaluate( + $limitation, + $currentUserReference, + $object, + $this->prepareTargetsForType($targets, $type) + ); return $accessVote === LimitationType::ACCESS_GRANTED; } @@ -366,7 +371,12 @@ private function isDeniedByRoleLimitation( } $type = $this->limitationService->getLimitationType($limitation->getIdentifier()); - $accessVote = $type->evaluate($limitation, $currentUserReference, $object, $targets); + $accessVote = $type->evaluate( + $limitation, + $currentUserReference, + $object, + $this->prepareTargetsForType($targets, $type) + ); return $accessVote === LimitationType::ACCESS_DENIED; }