src/EventSubscriber/TimeEntryEventSubscriber.php line 30

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace App\EventSubscriber;
  3. use ApiPlatform\Core\Api\IriConverterInterface;
  4. use ApiPlatform\Core\EventListener\EventPriorities;
  5. use App\Entity\TimeControl\TimeEntry;
  6. use App\Entity\User;
  7. use App\Repository\UserRepository;
  8. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpKernel\Event\ViewEvent;
  11. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  12. use Symfony\Component\HttpKernel\KernelEvents;
  13. use Symfony\Component\Security\Core\Security;
  14. class TimeEntryEventSubscriber implements EventSubscriberInterface
  15. {
  16.     public function __construct(private Security $security, private IriConverterInterface $iriConverter, private UserRepository $repository)
  17.     {
  18.     }
  19.     public static function getSubscribedEvents(): array
  20.     {
  21.         return [
  22.             KernelEvents::VIEW => ['checkRoles'EventPriorities::PRE_WRITE],
  23.         ];
  24.     }
  25.     public function checkRoles(ViewEvent $event): void
  26.     {
  27.         $originTimeEntry $event->getControllerResult();
  28.         if (!$originTimeEntry instanceof TimeEntry) {
  29.             return;
  30.         }
  31.         if ($event->getRequest()->getMethod() === Request::METHOD_DELETE) {
  32.             $this->checkRolesOnDelete($originTimeEntry);
  33.         }
  34.         if (\in_array($event->getRequest()->getMethod(), [Request::METHOD_POSTRequest::METHOD_PUT], true)) {
  35.             $this->checkRoleOnChange($event$originTimeEntry);
  36.         }
  37.     }
  38.     protected function checkRolesOnDelete(TimeEntry $originTimeEntry): void
  39.     {
  40.         $user $this->security->getUser();
  41.         if (!$user instanceof User) {
  42.             return;
  43.         }
  44.         if (!$this->security->isGranted('ROLE_MANAGER') && $originTimeEntry->getUser() !== $user) {
  45.             throw new AccessDeniedHttpException('You cannot delete another user\'s entry');
  46.         }
  47.         if ($this->security->isGranted('ROLE_MANAGER') && !$this->security->isGranted('ROLE_ADMIN')) {
  48.             $manager $user->getManager();
  49.             $originProject $originTimeEntry->getProject();
  50.             if ($originTimeEntry->getUser() !== $user) {
  51.                 if ($originProject) {
  52.                     if (!$originProject->getManagers()->contains($manager)) {
  53.                         throw new AccessDeniedHttpException('You cannot delete an entry not in your project');
  54.                     }
  55.                 } else {
  56.                     throw new AccessDeniedHttpException('You cannot delete the entry for this user outside the project');
  57.                 }
  58.             }
  59.         }
  60.     }
  61.     protected function checkRoleOnChange(ViewEvent $eventTimeEntry $originTimeEntry): void
  62.     {
  63.         $content $event->getRequest()->getContent();
  64.         if (!\is_string($content)) {
  65.             throw new \RuntimeException('Request content must be a string');
  66.         }
  67.         try {
  68.             $requestData \json_decode($contenttrue512JSON_THROW_ON_ERROR);
  69.         } catch (\JsonException $e) {
  70.             throw new \RuntimeException($e->getMessage());
  71.         }
  72.         $user $this->security->getUser();
  73.         if (!$user instanceof User) {
  74.             throw new \RuntimeException('Cannot get user from security service');
  75.         }
  76.         $targetUser $this->loadUser($requestData['user'] ?? null);
  77.         if ($targetUser === null) {
  78.             return;
  79.         }
  80.         if ($this->security->isGranted('ROLE_USER') && !$this->security->isGranted('ROLE_MANAGER')) {
  81.             if ($targetUser !== $user) {
  82.                 throw new AccessDeniedHttpException('You cannot change your entry to another user\'s entry');
  83.             }
  84.             if ($originTimeEntry->getUser() !== $user) {
  85.                 throw new AccessDeniedHttpException('You cannot change another user\'s entry');
  86.             }
  87.         }
  88.         if ($this->security->isGranted('ROLE_MANAGER') && !$this->security->isGranted('ROLE_ADMIN')) {
  89.             $manager $user->getManager();
  90.             $originProject $originTimeEntry->getProject();
  91.             if ($originTimeEntry->getUser() !== $user) {
  92.                 if ($originProject) {
  93.                     if (!$originProject->getManagers()->contains($manager)) {
  94.                         throw new AccessDeniedHttpException('You cannot change an entry not in your project');
  95.                     }
  96.                 } else {
  97.                     throw new AccessDeniedHttpException('You cannot change the entry for this user outside the project');
  98.                 }
  99.             }
  100.         }
  101.     }
  102.     private function loadUser(?string $iri): ?User
  103.     {
  104.         if ($iri === null) {
  105.             return null;
  106.         }
  107.         $slug \pathinfo($iriPATHINFO_FILENAME);
  108.         return $this->repository->findOneBy(['slug' => $slug]);
  109.     }
  110. }