diff --git a/src/Security/Voter/OrderdetailVoter.php b/src/Security/Voter/OrderdetailVoter.php index 84a2b739..3fb6a566 100644 --- a/src/Security/Voter/OrderdetailVoter.php +++ b/src/Security/Voter/OrderdetailVoter.php @@ -25,30 +25,60 @@ namespace App\Security\Voter; use App\Entity\PriceInformations\Orderdetail; use App\Entity\UserSystem\User; +use App\Services\PermissionResolver; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Security; class OrderdetailVoter extends ExtendedVoter { - /** - * @var string[] When this permsission are encountered, they are checked on part - */ - protected const PART_PERMS = ['show_history', 'revert_element']; + protected Security $security; + + public function __construct(PermissionResolver $resolver, EntityManagerInterface $entityManager, Security $security) + { + parent::__construct($resolver, $entityManager); + $this->security = $security; + } + + protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; protected function voteOnUser(string $attribute, $subject, User $user): bool { - if (in_array($attribute, self::PART_PERMS, true)) { - return $this->resolver->inherit($user, 'parts', $attribute) ?? false; + if (! is_a($subject, Orderdetail::class, true)) { + throw new \RuntimeException('This voter can only handle Orderdetail objects!'); } - return $this->resolver->inherit($user, 'parts_orderdetails', $attribute) ?? false; + switch ($attribute) { + case 'read': + $operation = 'read'; + break; + case 'edit': //As long as we can edit, we can also edit orderdetails + case 'create': + case 'delete': + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new \RuntimeException('Encountered unknown operation "'.$attribute.'"!'); + } + + //If we have no part associated use the generic part permission + if (is_string($subject) || $subject->getPart() === null) { + return $this->resolver->inherit($user, 'parts', $operation) ?? false; + } + + //Otherwise vote on the part + return $this->security->isGranted($attribute, $subject->getPart()); } protected function supports($attribute, $subject): bool { if (is_a($subject, Orderdetail::class, true)) { - return in_array($attribute, array_merge( - self::PART_PERMS, - $this->resolver->listOperationsForPermission('parts_orderdetails') - ), true); + return in_array($attribute, self::ALLOWED_PERMS, true); } return false; diff --git a/src/Security/Voter/ParameterVoter.php b/src/Security/Voter/ParameterVoter.php index 503b5bcd..7135ad08 100644 --- a/src/Security/Voter/ParameterVoter.php +++ b/src/Security/Voter/ParameterVoter.php @@ -46,17 +46,31 @@ class ParameterVoter extends ExtendedVoter $target_element = $subject->getElement(); if ($target_element !== null) { //Depending on the operation delegate either to the attachments element or to the attachment permission + + switch ($attribute) { //We can view the attachment if we can view the element case 'read': case 'view': - return $this->security->isGranted('read', $target_element); + $operation = 'read'; + break; //We can edit/create/delete the attachment if we can edit the element case 'edit': case 'create': case 'delete': - return $this->security->isGranted('edit', $target_element); + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new RuntimeException('Unknown operation: '.$attribute); } + + return $this->security->isGranted($operation, $target_element); } //If we do not have a concrete element, we delegate to the different categories @@ -93,7 +107,7 @@ class ParameterVoter extends ExtendedVoter { if (is_a($subject, AbstractParameter::class, true)) { //These are the allowed attributes - return in_array($attribute, ['read', 'edit', 'delete', 'create'], true); + return in_array($attribute, ['read', 'edit', 'delete', 'create', 'show_history', 'revert_element'], true); } //Allow class name as subject diff --git a/src/Security/Voter/PartLotVoter.php b/src/Security/Voter/PartLotVoter.php index 2fc8f608..b61525ce 100644 --- a/src/Security/Voter/PartLotVoter.php +++ b/src/Security/Voter/PartLotVoter.php @@ -24,31 +24,62 @@ declare(strict_types=1); namespace App\Security\Voter; use App\Entity\Parts\PartLot; +use App\Entity\PriceInformations\Orderdetail; use App\Entity\UserSystem\User; +use App\Services\PermissionResolver; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Security; class PartLotVoter extends ExtendedVoter { - /** - * @var string[] When this permsission are encountered, they are checked on part - */ - protected const PART_PERMS = ['show_history', 'revert_element']; + protected Security $security; + + public function __construct(PermissionResolver $resolver, EntityManagerInterface $entityManager, Security $security) + { + parent::__construct($resolver, $entityManager); + $this->security = $security; + } + + protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; protected function voteOnUser(string $attribute, $subject, User $user): bool { - if (in_array($attribute, self::PART_PERMS, true)) { - return $this->resolver->inherit($user, 'parts', $attribute) ?? false; + if (! is_a($subject, PartLot::class, true)) { + throw new \RuntimeException('This voter can only handle PartLot objects!'); } - return $this->resolver->inherit($user, 'parts_lots', $attribute) ?? false; + switch ($attribute) { + case 'read': + $operation = 'read'; + break; + case 'edit': //As long as we can edit, we can also edit orderdetails + case 'create': + case 'delete': + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new \RuntimeException('Encountered unknown operation "'.$attribute.'"!'); + } + + //If we have no part associated use the generic part permission + if (is_string($subject) || $subject->getPart() === null) { + return $this->resolver->inherit($user, 'parts', $operation) ?? false; + } + + //Otherwise vote on the part + return $this->security->isGranted($attribute, $subject->getPart()); } protected function supports($attribute, $subject): bool { if (is_a($subject, PartLot::class, true)) { - return in_array($attribute, array_merge( - self::PART_PERMS, - $this->resolver->listOperationsForPermission('parts_lots') - ), true); + return in_array($attribute, self::ALLOWED_PERMS, true); } return false; diff --git a/src/Security/Voter/PricedetailVoter.php b/src/Security/Voter/PricedetailVoter.php index b21b367f..2f1140a5 100644 --- a/src/Security/Voter/PricedetailVoter.php +++ b/src/Security/Voter/PricedetailVoter.php @@ -23,32 +23,63 @@ declare(strict_types=1); namespace App\Security\Voter; +use App\Entity\Parts\PartLot; use App\Entity\PriceInformations\Pricedetail; use App\Entity\UserSystem\User; +use App\Services\PermissionResolver; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Security; class PricedetailVoter extends ExtendedVoter { - /** - * @var string[] When this permsission are encountered, they are checked on part - */ - protected const PART_PERMS = ['show_history', 'revert_element']; + protected Security $security; + + public function __construct(PermissionResolver $resolver, EntityManagerInterface $entityManager, Security $security) + { + parent::__construct($resolver, $entityManager); + $this->security = $security; + } + + protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; protected function voteOnUser(string $attribute, $subject, User $user): bool { - if (in_array($attribute, self::PART_PERMS, true)) { - return $this->resolver->inherit($user, 'parts', $attribute) ?? false; + if (!is_a($subject, Pricedetail::class, true)) { + throw new \RuntimeException('This voter can only handle Pricedetails objects!'); } - return $this->resolver->inherit($user, 'parts_prices', $attribute) ?? false; + switch ($attribute) { + case 'read': + $operation = 'read'; + break; + case 'edit': //As long as we can edit, we can also edit orderdetails + case 'create': + case 'delete': + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new \RuntimeException('Encountered unknown operation "'.$attribute.'"!'); + } + + //If we have no part associated use the generic part permission + if (is_string($subject) || $subject->getOrderdetail() === null || $subject->getOrderdetail()->getPart() === null) { + return $this->resolver->inherit($user, 'parts', $operation) ?? false; + } + + //Otherwise vote on the part + return $this->security->isGranted($attribute, $subject->getOrderdetail()->getPart()); } protected function supports($attribute, $subject): bool { if (is_a($subject, Pricedetail::class, true)) { - return in_array($attribute, array_merge( - self::PART_PERMS, - $this->resolver->listOperationsForPermission('parts_prices') - ), true); + return in_array($attribute, self::ALLOWED_PERMS, true); } return false;