<?php
namespace App\Security\Placement\PaymentPlan;
use ApiPlatform\Core\Api\IriConverterInterface;
use App\Entity\Formula;
use App\Entity\Placement\Pdf\PaymentPlan\Config\Config;
use App\Entity\Placement\Pdf\PaymentPlan\Config\Group\Group;
use App\Entity\Placement\Pdf\PaymentPlan\Config\Group\Payment\AdvancedSumPayment;
use App\Entity\Placement\Pdf\PaymentPlan\Config\Group\Payment\Formula\AdvancedFormula;
use App\Entity\Placement\Pdf\PaymentPlan\Config\Group\Payment\OneLinePayment;
use App\Entity\Placement\Pdf\PaymentPlan\PaymentPlan;
use App\Entity\Placement\Pdf\PaymentPlan\UnitInfo\SystemValueInfo;
use App\Entity\Placement\Pdf\PaymentPlan\UnitInfo\UnitInfo;
use App\Entity\PlacementProperty;
use App\Security\EntityVoters\EntityVoter;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\User\UserInterface;
class PaymentPlanVoter extends EntityVoter
{
private IriConverterInterface $iriConverter;
private UserInterface $user;
public function __construct(IriConverterInterface $iriConverter, RouterInterface $router, RequestStack $requestStack)
{
$this->iriConverter = $iriConverter;
parent::__construct($router,$requestStack);
}
/**
* @param string $attribute
* @param $subject PaymentPlan
* @param TokenInterface $token
* @return bool
*/
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$this->user = $token->getUser();
if (!$this->user)
return false;
if ($this->user && $this->user->getRole()->getName() === 'ROLE_SUPER_ADMIN')
return true;
switch ($attribute)
{
case 'GET_COLLECTION':
print_r("GET_ALL\n");
return true;
break;
case 'GET' :
print_r("GET_ONE DELETE\n");
if (!$subject->getComplex()->isUserHasAccess($this->user))
return false;
break;
case 'PATCH':
print_r("PATCH PUT\n");
if (!$subject->getComplex()->isUserHasAccess($this->user))
return false;
break;
case 'PUT':
break;
case 'DELETE':
break;
case 'POST':
print_r("POST\n");
break;
case 'POST_DENORMALIZE':
return $this->checkPost($subject);
break;
}
return false;
}
private function checkPost(PaymentPlan $paymentPlan): bool {
if ($paymentPlan->getComplex() && !$paymentPlan->getComplex()->isUserHasAccess($this->user))
throw new AccessDeniedException("U have no access to set given complex with id: {$paymentPlan->getComplex()->getId()}", null);
$this->checkLinkedPlacements($paymentPlan);
$this->checkLinkedUnitInfos($paymentPlan->getUnitInfos());
$this->checkLinkedConfig($paymentPlan->getConfig());
return true;
}
/**
* @param PaymentPlan $paymentPlan
* @return void
*/
private function checkLinkedPlacements(PaymentPlan $paymentPlan): void {
if (($placements = $paymentPlan->getPlacements()) && $placements->count() > 0) {
foreach ($placements as $placement) {
if (!$placement->getComplex()->isUserHasAccess($this->user)) {
throw new AccessDeniedException("U have no access to add given placement with id: {$placement->getId()}");
} else if ($paymentPlan->getComplex()->getId() !== $placement->getComplex()->getId())
throw new AccessDeniedException("U have no access to add given placement with id: {$placement->getId()} because it belongs to another complex.");
}
}
}
/**
* @param Collection<int, UnitInfo>|null $unitInfos
* @return void
*/
private function checkLinkedUnitInfos(?Collection $unitInfos): void {
if ($unitInfos && $unitInfos->count() > 0) {
foreach ($unitInfos as $unitInfo) {
if ($unitInfo instanceof SystemValueInfo && $unitInfo->getPlacementProperty()) {
if (!$unitInfo->getPlacementProperty()->getComplex()->isUserHasAccess($this->user))
throw new AccessDeniedException("U have no access to add to unitInfos given placement property with id: {$unitInfo->getPlacementProperty()->getId()} ");
}
}
}
}
/**
* @param Config|null $config
* @return void
*/
private function checkLinkedConfig(?Config $config): void {
if ($config && ($groups = $config->getGroups()) && $groups->count() > 0) {
$this->checkLinkedGroups($config->getGroups());
}
}
/**
* @param Collection<int, Group>|null $groups
* @return void
*/
private function checkLinkedGroups(?Collection $groups) {
if ($groups && $groups->count() > 0)
foreach ($groups as $group) {
$this->checkLinkedPayments($group->getPayments());
}
}
private function checkLinkedPayments(?Collection $payments) {
if ($payments && $payments->count() > 0) {
foreach ($payments as $payment) {
if ($payment instanceof OneLinePayment) {
$this->checkLinkedFormula($payment->getFormula());
} else if ($payment instanceof AdvancedSumPayment) {
$this->checkAdvancedFormulas($payment->getAdvancedFormulas());
}
}
}
}
private function checkLinkedFormula(?Formula $formula) {
if ($formula && ($formulaMembers = $formula->getFormulaMembers())) {
foreach ($formulaMembers as $formulaMember) {
if (strpos($formulaMember, '/api/') !== false) {
$resource = $this->iriConverter->getItemFromIri($formulaMember);
if ($resource instanceof PlacementProperty) {
if (!$resource->getComplex()->isUserHasAccess($this->user)) {
throw new AccessDeniedException("U have no access to add to oneLinePayment given placement property with id: {$resource->getId()} ");
}
}
}
}
}
}
/**
* @param Collection<int, AdvancedFormula>|null $advancedFormulas
* @return void
*/
private function checkAdvancedFormulas(?Collection $advancedFormulas) {
if ($advancedFormulas && $advancedFormulas->count() > 0) {
foreach ($advancedFormulas as $advancedFormula) {
$this->checkLinkedFormula($advancedFormula->getFormula());
}
}
}
private function isAllowedPost($user, PaymentPlan $subject): bool {
if (!$user)
return false;
if ($subject->getComplex()->isUserHasAccess($user))
return true;
return false;
}
protected function getVoteEntityClass(): string
{
return PaymentPlan::class;
}
}