|
|
@@ -0,0 +1,199 @@
|
|
|
+<?php
|
|
|
+declare(strict_types=1);
|
|
|
+
|
|
|
+namespace App\Security\Voter;
|
|
|
+
|
|
|
+use App\Entity\Access\Access;
|
|
|
+use App\Entity\Core\BankAccount;
|
|
|
+use App\Entity\Core\File;
|
|
|
+use AppBundle\Entity\Organization\Organization;
|
|
|
+use AppBundle\Entity\Person\Person;
|
|
|
+use AppBundle\Enum\Core\FileTypeEnum;
|
|
|
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
|
|
+use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
|
|
+use Symfony\Bundle\SecurityBundle\Security;
|
|
|
+use Symfony\Component\Security\Core\User\UserInterface;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Contrôle l'accès à l'entité File
|
|
|
+ */
|
|
|
+class FileVoter extends AbstractVoter
|
|
|
+{
|
|
|
+ protected const FILE_READ = 'FILE_READ';
|
|
|
+ protected const FILE_EDIT = 'FILE_EDIT';
|
|
|
+ protected const FILE_CREATE = 'FILE_CREATE';
|
|
|
+ protected const FILE_DELETE = 'FILE_DELETE';
|
|
|
+
|
|
|
+ public function __construct(
|
|
|
+ private Security $security
|
|
|
+ ) {}
|
|
|
+
|
|
|
+ protected function supports(string $attribute, $subject): bool
|
|
|
+ {
|
|
|
+ return $subject instanceof File && in_array($attribute, [self::FILE_READ, self::FILE_EDIT, self::FILE_DELETE]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Retourne True si l'utilisateur a le droit d'effectuer l'opération demandée
|
|
|
+ *
|
|
|
+ * @param string $attribute
|
|
|
+ * @param mixed $subject
|
|
|
+ * @param TokenInterface $token
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
|
|
|
+ {
|
|
|
+ if(!$this->isAvailabilityDatePassed($subject)) {
|
|
|
+ // Le fichier n'est pas encore disponible TODO: à revoir
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch ($attribute) {
|
|
|
+ case self::FILE_READ:
|
|
|
+ return $this->canView($subject);
|
|
|
+ case self::FILE_EDIT:
|
|
|
+ return $this->canEdit($subject, $user);
|
|
|
+ case self::FILE_CREATE:
|
|
|
+ return $this->canCreate($subject, $user);
|
|
|
+ case self::FILE_DELETE:
|
|
|
+ return $this->canDelete($subject, $user);
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns True if the current user has the right to GET this record
|
|
|
+ *
|
|
|
+ * @param $subject \AppBundle\Entity\Core\File
|
|
|
+ * @param $user
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ public function canView(File $subject): bool
|
|
|
+ {
|
|
|
+ // File has public visibility
|
|
|
+ if ($subject->getVisibility() === FileVisibilityEnum::EVERYBODY) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Is this an internal request? (@see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/doc/internal_requests.md)
|
|
|
+ $clientIp = $_SERVER['REMOTE_ADDR'];
|
|
|
+ $internalRequestToken = $_SERVER['HTTP_INTERNAL_REQUESTS_TOKEN'] ?? '';
|
|
|
+ if ($this->internalRequestsService->isAllowed($clientIp, $internalRequestToken)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the user has not logged in, the file is not available
|
|
|
+ if (!$this->user) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the logged user is in accessUser of File
|
|
|
+ if ($subject->getAccessPersons()->count() !== 0) {
|
|
|
+ foreach ($subject->getAccessPersons() as $accessPerson) {
|
|
|
+ if ($user->getId() == $accessPerson->getId()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * If the logged user is in accessRole of File
|
|
|
+ */
|
|
|
+ if(0 !== count($subject->getAccessRoles())
|
|
|
+ &&(
|
|
|
+ ($subject->getOrganization() instanceof Organization && $subject->getOrganization()->getId() === $this->accessService->getAccess()->getOrganization()->getId())
|
|
|
+ || ($subject->getPerson() instanceof Person && $subject->getPerson()->getId() === $this->accessService->getAccess()->getPerson()->getId())
|
|
|
+ )
|
|
|
+ ){
|
|
|
+ foreach ($subject->getAccessRoles() as $accessRole){
|
|
|
+ if($this->accessService->hasRole($accessRole)){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param $subject \AppBundle\Entity\Core\File
|
|
|
+ * @param $user
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ public function canEdit($subject, $user)
|
|
|
+ {
|
|
|
+ /**
|
|
|
+ * If user is not logged, the file is not available
|
|
|
+ */
|
|
|
+ if (!$user instanceof Person) {
|
|
|
+ return false;
|
|
|
+ } /**
|
|
|
+ * If user has ROLE_FILE
|
|
|
+ */
|
|
|
+ elseif ($this->accessService->hasRole('ROLE_FILE')
|
|
|
+ && (
|
|
|
+ ($subject->getOrganization() instanceof Organization && $subject->getOrganization()->getId() === $this->accessService->getAccess()->getOrganization()->getId())
|
|
|
+ || ($subject->getPerson() instanceof Person && $subject->getPerson()->getId() === $this->accessService->getAccess()->getPerson()->getId())
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ return true;
|
|
|
+ } /**
|
|
|
+ * If proprietary person of file is same of logged user
|
|
|
+ */
|
|
|
+ elseif ($subject->getPerson() instanceof Person && $subject->getPerson()->getId() === $user->getId()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param $subject File
|
|
|
+ * @param $user
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ public function canCreate($subject, $user)
|
|
|
+ {
|
|
|
+ /**
|
|
|
+ * If user is not logged, the file is not available
|
|
|
+ */
|
|
|
+ if (!$user instanceof Person) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param $subject File
|
|
|
+ * @param $user
|
|
|
+ * @return boolean
|
|
|
+ */
|
|
|
+ public function canDelete($subject, $user){
|
|
|
+ return $this->canEdit($subject, $user);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param $subject
|
|
|
+ * @return bool
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ private function isAvailabilityDatePassed($subject){
|
|
|
+ $isAvailabilityDatePassed = true;
|
|
|
+
|
|
|
+ $today = new \DateTime();
|
|
|
+ if (!empty($subject->getAvailabilityDate()) && $subject->getAvailabilityDate() > $today) {
|
|
|
+ $userHasRole = false;
|
|
|
+ // Si l'utilisateur a les droits suffisant pour voir le fichier meme si la date n'est pas passé: exemple: liste des factures
|
|
|
+ if($subject->getType() === FileTypeEnum::BILL && $this->roleServiceUtils->checkIfUserHasRoles($this->accessService->getRoles(), ['ROLE_BILLACCOUNTING'])){
|
|
|
+ $userHasRole = true;
|
|
|
+ }
|
|
|
+ if(!$userHasRole)
|
|
|
+ $isAvailabilityDatePassed = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return $isAvailabilityDatePassed;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|