diff --git a/src/Domain/User/Specification/CanUserEditOrganization.php b/src/Domain/User/Specification/CanUserEditOrganization.php new file mode 100644 index 000000000..bbf6d80de --- /dev/null +++ b/src/Domain/User/Specification/CanUserEditOrganization.php @@ -0,0 +1,25 @@ +getOrganizationUsers() as $organizationUser) { + if ($organizationUser->uuid !== $organization->getUuid()) { + continue; + } + + return \in_array(OrganizationRolesEnum::ROLE_ORGA_ADMIN->value, $organizationUser->roles); + } + + return false; + } +} diff --git a/src/Domain/User/Specification/CanUserViewOrganization.php b/src/Domain/User/Specification/CanUserViewOrganization.php new file mode 100644 index 000000000..63823a93f --- /dev/null +++ b/src/Domain/User/Specification/CanUserViewOrganization.php @@ -0,0 +1,16 @@ +getUuid(), $user->getOrganizationUuids()); + } +} diff --git a/src/Infrastructure/Security/Voter/OrganizationVoter.php b/src/Infrastructure/Security/Voter/OrganizationVoter.php index dbeb2196a..ada877680 100644 --- a/src/Infrastructure/Security/Voter/OrganizationVoter.php +++ b/src/Infrastructure/Security/Voter/OrganizationVoter.php @@ -4,8 +4,9 @@ namespace App\Infrastructure\Security\Voter; -use App\Domain\User\Enum\OrganizationRolesEnum; use App\Domain\User\Organization; +use App\Domain\User\Specification\CanUserEditOrganization; +use App\Domain\User\Specification\CanUserViewOrganization; use App\Infrastructure\Security\SymfonyUser; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; @@ -15,6 +16,12 @@ final class OrganizationVoter extends Voter public const VIEW = 'view'; public const EDIT = 'edit'; + public function __construct( + private readonly CanUserEditOrganization $canUserEditOrganization, + private readonly CanUserViewOrganization $canUserViewOrganization, + ) { + } + protected function supports(string $attribute, mixed $subject): bool { if (!\in_array($attribute, [self::VIEW, self::EDIT])) { @@ -40,27 +47,9 @@ protected function voteOnAttribute(string $attribute, mixed $subject, TokenInter $organization = $subject; return match ($attribute) { - self::VIEW => $this->canView($organization, $user), - self::EDIT => $this->canEdit($organization, $user), + self::VIEW => $this->canUserViewOrganization->isSatisfiedBy($organization, $user), + self::EDIT => $this->canUserEditOrganization->isSatisfiedBy($organization, $user), default => throw new \LogicException('This code should not be reached!') }; } - - private function canView(Organization $organization, SymfonyUser $user): bool - { - return \in_array($organization->getUuid(), $user->getOrganizationUuids()); - } - - private function canEdit(Organization $organization, SymfonyUser $user): bool - { - foreach ($user->getOrganizationUsers() as $organizationUser) { - if ($organizationUser->uuid !== $organization->getUuid()) { - continue; - } - - return \in_array(OrganizationRolesEnum::ROLE_ORGA_ADMIN->value, $organizationUser->roles); - } - - return false; - } } diff --git a/tests/Unit/Domain/User/Specification/CanUserEditOrganizationTest.php b/tests/Unit/Domain/User/Specification/CanUserEditOrganizationTest.php new file mode 100644 index 000000000..83a7e98dc --- /dev/null +++ b/tests/Unit/Domain/User/Specification/CanUserEditOrganizationTest.php @@ -0,0 +1,55 @@ +createMock(Organization::class); + $organization + ->expects(self::once()) + ->method('getUuid') + ->willReturn('c1790745-b915-4fb5-96e7-79b104092a55'); + + $symfonyUser = $this->createMock(SymfonyUser::class); + $symfonyUser + ->expects(self::once()) + ->method('getOrganizationUsers') + ->willReturn([ + new OrganizationView('c1790745-b915-4fb5-96e7-79b104092a55', 'Dialog', [OrganizationRolesEnum::ROLE_ORGA_ADMIN->value]), + ]); + + $pattern = new CanUserEditOrganization(); + $this->assertTrue($pattern->isSatisfiedBy($organization, $symfonyUser)); + } + + public function testCannotEdit(): void + { + $organization = $this->createMock(Organization::class); + $organization + ->expects(self::once()) + ->method('getUuid') + ->willReturn('c1790745-b915-4fb5-96e7-79b104092a55'); + + $symfonyUser = $this->createMock(SymfonyUser::class); + $symfonyUser + ->expects(self::once()) + ->method('getOrganizationUsers') + ->willReturn([ + new OrganizationView('c1790745-b915-4fb5-96e7-79b104092a55', 'Dialog', [OrganizationRolesEnum::ROLE_ORGA_CONTRIBUTOR->value]), + ]); + + $pattern = new CanUserEditOrganization(); + $this->assertFalse($pattern->isSatisfiedBy($organization, $symfonyUser)); + } +} diff --git a/tests/Unit/Domain/User/Specification/CanUserPublishRegulationTest.php b/tests/Unit/Domain/User/Specification/CanUserPublishRegulationTest.php index e142a1526..3ea267657 100644 --- a/tests/Unit/Domain/User/Specification/CanUserPublishRegulationTest.php +++ b/tests/Unit/Domain/User/Specification/CanUserPublishRegulationTest.php @@ -40,7 +40,7 @@ public function testCanPublish(): void $this->assertTrue($pattern->isSatisfiedBy($regulationOrderRecord, $symfonyUser)); } - public function testCantPublish(): void + public function testCannotPublish(): void { $organization = $this->createMock(Organization::class); $organization diff --git a/tests/Unit/Domain/User/Specification/CanUserViewOrganizationTest.php b/tests/Unit/Domain/User/Specification/CanUserViewOrganizationTest.php new file mode 100644 index 000000000..39107e152 --- /dev/null +++ b/tests/Unit/Domain/User/Specification/CanUserViewOrganizationTest.php @@ -0,0 +1,49 @@ +createMock(Organization::class); + $organization + ->expects(self::once()) + ->method('getUuid') + ->willReturn('c1790745-b915-4fb5-96e7-79b104092a55'); + + $symfonyUser = $this->createMock(SymfonyUser::class); + $symfonyUser + ->expects(self::once()) + ->method('getOrganizationUuids') + ->willReturn(['c1790745-b915-4fb5-96e7-79b104092a55']); + + $pattern = new CanUserViewOrganization(); + $this->assertTrue($pattern->isSatisfiedBy($organization, $symfonyUser)); + } + + public function testCannotView(): void + { + $organization = $this->createMock(Organization::class); + $organization + ->expects(self::once()) + ->method('getUuid') + ->willReturn('28aaef2a-e9d1-4189-9ead-17e866a8726f'); + + $symfonyUser = $this->createMock(SymfonyUser::class); + $symfonyUser + ->expects(self::once()) + ->method('getOrganizationUuids') + ->willReturn(['c1790745-b915-4fb5-96e7-79b104092a55']); + + $pattern = new CanUserViewOrganization(); + $this->assertFalse($pattern->isSatisfiedBy($organization, $symfonyUser)); + } +}