From d52108589269329a8e5b13f0fd2086d4f50367f7 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 2 Apr 2025 16:03:56 +0200 Subject: [PATCH 1/6] Add validation: enough charge for reward --- src/Validator/EnoughRewardCharge.php | 16 +++++++++ src/Validator/EnoughRewardChargeValidator.php | 33 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/Validator/EnoughRewardCharge.php create mode 100644 src/Validator/EnoughRewardChargeValidator.php diff --git a/src/Validator/EnoughRewardCharge.php b/src/Validator/EnoughRewardCharge.php new file mode 100644 index 0000000..f1bcb3c --- /dev/null +++ b/src/Validator/EnoughRewardCharge.php @@ -0,0 +1,16 @@ +charge->money; + $reward = $value->reward->money; + + if ($this->money->isMoreOrSame($charge, $reward)) { + return; + } + + $this->context->buildViolation($constraint->message) + ->addViolation() + ; + } +} From 8d47357f617a87263ea84f305234e2663af3a23e Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 2 Apr 2025 16:22:24 +0200 Subject: [PATCH 2/6] Add validation: available reward units for claim --- src/Validator/AvailableRewardUnits.php | 11 +++++++ .../AvailableRewardUnitsValidator.php | 29 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/Validator/AvailableRewardUnits.php create mode 100644 src/Validator/AvailableRewardUnitsValidator.php diff --git a/src/Validator/AvailableRewardUnits.php b/src/Validator/AvailableRewardUnits.php new file mode 100644 index 0000000..1414e62 --- /dev/null +++ b/src/Validator/AvailableRewardUnits.php @@ -0,0 +1,11 @@ +hasUnits && $value->unitsAvailable > 0) { + return; + } + + if ($value === null || $value === '') { + return; + } + + $this->context->buildViolation($constraint->message) + ->setParameter('{{ id }}', $value->id) + ->addViolation() + ; + } +} From 1f762af4288dda8d500aab4b35b38f5a3f05fe96 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 2 Apr 2025 16:22:49 +0200 Subject: [PATCH 3/6] Update reward claim model --- .../Project/RewardClaimApiResource.php | 23 ++++++++++++++----- src/Entity/Project/RewardClaim.php | 17 ++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/ApiResource/Project/RewardClaimApiResource.php b/src/ApiResource/Project/RewardClaimApiResource.php index f9c1d38..6ddfd97 100644 --- a/src/ApiResource/Project/RewardClaimApiResource.php +++ b/src/ApiResource/Project/RewardClaimApiResource.php @@ -4,10 +4,13 @@ namespace App\ApiResource\Project; use ApiPlatform\Doctrine\Orm\State\Options; use ApiPlatform\Metadata as API; +use App\ApiResource\Gateway\ChargeApiResource; use App\ApiResource\User\UserApiResource; use App\Entity\Project\RewardClaim; use App\State\ApiResourceStateProvider; use App\State\Project\RewardClaimStateProcessor; +use App\Validator\AvailableRewardUnits; +use App\Validator\EnoughRewardCharge; use Symfony\Component\Validator\Constraints as Assert; /** @@ -19,20 +22,28 @@ use Symfony\Component\Validator\Constraints as Assert; provider: ApiResourceStateProvider::class, processor: RewardClaimStateProcessor::class )] +#[EnoughRewardCharge()] class RewardClaimApiResource { #[API\ApiProperty(identifier: true, writable: false)] public int $id; - /** - * The ProjectReward being claimed. - */ - #[Assert\NotBlank()] - public RewardApiResource $reward; - /** * The User claiming the ProjectReward. */ #[API\ApiProperty(writable: false)] public UserApiResource $owner; + + /** + * The GatewayCharge granting access to the ProjectReward. + */ + #[Assert\NotBlank()] + public ChargeApiResource $charge; + + /** + * The ProjectReward being claimed. + */ + #[Assert\NotBlank()] + #[AvailableRewardUnits()] + public RewardApiResource $reward; } diff --git a/src/Entity/Project/RewardClaim.php b/src/Entity/Project/RewardClaim.php index feecac3..1707ea5 100644 --- a/src/Entity/Project/RewardClaim.php +++ b/src/Entity/Project/RewardClaim.php @@ -2,6 +2,7 @@ namespace App\Entity\Project; +use App\Entity\Gateway\Charge; use App\Entity\Interface\UserOwnedInterface; use App\Entity\Trait\UserOwnedTrait; use App\Entity\User\User; @@ -22,6 +23,10 @@ class RewardClaim implements UserOwnedInterface #[ORM\Column] private ?int $id = null; + #[ORM\OneToOne(cascade: ['persist', 'remove'])] + #[ORM\JoinColumn(nullable: false)] + private ?Charge $charge = null; + #[ORM\ManyToOne(inversedBy: 'claims')] #[ORM\JoinColumn(nullable: false)] private ?Reward $reward = null; @@ -35,6 +40,18 @@ class RewardClaim implements UserOwnedInterface return $this->id; } + public function getCharge(): ?Charge + { + return $this->charge; + } + + public function setCharge(Charge $charge): static + { + $this->charge = $charge; + + return $this; + } + public function getReward(): ?Reward { return $this->reward; From 7944ec8e5cd7d8d3b231601c2e70ba5daae3360f Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 2 Apr 2025 16:30:15 +0200 Subject: [PATCH 4/6] Update reward available units constraint validation --- src/Validator/AvailableRewardUnitsValidator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Validator/AvailableRewardUnitsValidator.php b/src/Validator/AvailableRewardUnitsValidator.php index 61dc0a3..bf51d40 100644 --- a/src/Validator/AvailableRewardUnitsValidator.php +++ b/src/Validator/AvailableRewardUnitsValidator.php @@ -13,11 +13,11 @@ final class AvailableRewardUnitsValidator extends ConstraintValidator */ public function validate(mixed $value, Constraint $constraint): void { - if ($value->hasUnits && $value->unitsAvailable > 0) { + if (!$value->hasUnits) { return; } - if ($value === null || $value === '') { + if ($value->hasUnits && $value->unitsAvailable > 0) { return; } From 5e673010c142deae33b676935337c83b78ee4b3d Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 2 Apr 2025 16:30:54 +0200 Subject: [PATCH 5/6] Remove reward service --- src/Service/Project/RewardService.php | 34 ------------------- .../Project/RewardClaimStateProcessor.php | 3 -- 2 files changed, 37 deletions(-) delete mode 100644 src/Service/Project/RewardService.php diff --git a/src/Service/Project/RewardService.php b/src/Service/Project/RewardService.php deleted file mode 100644 index 131c1c7..0000000 --- a/src/Service/Project/RewardService.php +++ /dev/null @@ -1,34 +0,0 @@ -getReward(); - - if (!$reward->hasUnits()) { - return $claim; - } - - $available = $reward->getUnitsAvailable(); - - if ($available < 1) { - throw new \Exception('The claimed Reward has no units available'); - } - - $reward->addClaim($claim); - $reward->setUnitsAvailable($available - 1); - - return $claim->setReward($reward); - } -} diff --git a/src/State/Project/RewardClaimStateProcessor.php b/src/State/Project/RewardClaimStateProcessor.php index d3c5a94..ea47d14 100644 --- a/src/State/Project/RewardClaimStateProcessor.php +++ b/src/State/Project/RewardClaimStateProcessor.php @@ -8,7 +8,6 @@ use App\ApiResource\Project\RewardClaimApiResource; use App\Entity\Project\RewardClaim; use App\Mapping\AutoMapper; use App\Service\Auth\AuthService; -use App\Service\Project\RewardService; use App\State\EntityStateProcessor; use Symfony\Component\Security\Core\Exception\AuthenticationException; @@ -18,7 +17,6 @@ class RewardClaimStateProcessor implements ProcessorInterface private EntityStateProcessor $entityStateProcessor, private AutoMapper $autoMapper, private AuthService $authService, - private RewardService $rewardService, ) {} /** @@ -41,7 +39,6 @@ class RewardClaimStateProcessor implements ProcessorInterface $claim->setOwner($owner); } - $claim = $this->rewardService->processClaim($claim); $claim = $this->entityStateProcessor->process($claim, $operation, $uriVariables, $context); return $this->autoMapper->map($claim, $data); From 2c6d09f8f21eb7861164615c8db50edaceeb6553 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 3 Apr 2025 13:19:41 +0200 Subject: [PATCH 6/6] Add docblock to support state processor --- src/State/Project/SupportStateProcessor.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/State/Project/SupportStateProcessor.php b/src/State/Project/SupportStateProcessor.php index ec3002e..9276961 100644 --- a/src/State/Project/SupportStateProcessor.php +++ b/src/State/Project/SupportStateProcessor.php @@ -21,9 +21,13 @@ class SupportStateProcessor implements ProcessorInterface private EntityManagerInterface $entityManager, ) {} + /** + * @param SupportApiResource $data + * + * @return SupportApiResource + */ public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []) { - // Verify if the user is authenticated $user = $this->authService->getUser(); if (!$user) { throw new AuthenticationException();