<?php
namespace App\Delivract\Security;
use App\Delivract\Entity\DocumentBailiff;
use App\Delivract\Entity\DocumentBailiffHistoryComment;
use App\Delivract\Enum\DocumentBailiffStatusEnum;
use AppBundle\Entity\User;
use AppBundle\Enum\FeatureAccessEnum;
use InvalidArgumentException;
use SettingsBundle\Enum\ModuleEnum;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
/**
* Class DocumentBailiffVoter
*/
class DocumentBailiffVoter extends Voter
{
public const CREATE = 'create';
public const COMMENT = 'comment';
public const SUSPEND = 'suspend';
public const CANCEL = 'cancel';
public const RESUME = 'resume';
public const ACCESS_DRIVE_FILE = 'access_drive_file';
public const DOWNLOAD_DRIVE_FILE = 'download_drive_file';
public const VIEW = 'view';
/**
* @var AccessDecisionManagerInterface
*/
private $decisionManager;
/**
* DocumentBailiffVoter constructor.
* @param AccessDecisionManagerInterface $decisionManager
*/
public function __construct(
AccessDecisionManagerInterface $decisionManager
) {
$this->decisionManager = $decisionManager;
}
/**
* {@inheritdoc}
*/
protected function supports($attribute, $subject): bool
{
if (!in_array(
$attribute,
[
self::CREATE,
self::COMMENT,
self::SUSPEND,
self::CANCEL,
self::RESUME,
self::ACCESS_DRIVE_FILE,
self::DOWNLOAD_DRIVE_FILE,
self::VIEW,
]
)) {
return false;
}
if (!$subject instanceof DocumentBailiff) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
if ($subject instanceof DocumentBailiffHistoryComment) {
/** @var DocumentBailiffHistoryComment $subject */
$subject = $subject->getDocumentBailiff();
}
if (!$subject instanceof DocumentBailiff) {
return false;
}
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
// the law firm's user need to module : MODULE_DELIVRACT
// the user need to have user module : USER_MODULE_DELIVRACT
if (!$user->getLawFirm()->hasModule(ModuleEnum::MODULE_DELIVRACT) ||
!$user->hasRole(ModuleEnum::USER_MODULE_DELIVRACT)) {
return false;
}
// only member of law firm owner can access this document
if ($subject->getLawFirm()->getId() !== $user->getLawFirm()->getId()) {
return false;
}
// Allow to see everything
/**
* @var bool $isAllAccess
*/
$isAllAccess = (bool) $this->decisionManager->decide($token, [FeatureAccessEnum::ALL_DOCUMENT_BAILIFF_ACCESS]);
switch ($attribute) {
case self::CREATE:
return $this->hasAccess($subject, $user, $isAllAccess);
case self::VIEW:
case self::COMMENT:
return $this->canView($subject, $user, $isAllAccess);
case self::ACCESS_DRIVE_FILE:
return $this->canAccessDriveFile($subject, $user, $isAllAccess);
case self::DOWNLOAD_DRIVE_FILE:
return $this->canDownloadDriveFile($subject, $user, $isAllAccess);
case self::SUSPEND:
return $this->canSuspend($subject, $user, $isAllAccess);
case self::CANCEL:
return $this->canCancel($subject, $user, $isAllAccess);
case self::RESUME:
return $this->canResume($subject, $user, $isAllAccess);
default:
throw new InvalidArgumentException('Invalid attribute');
}
}
/**
* @param DocumentBailiff $documentBailiff
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canSuspend(DocumentBailiff $documentBailiff, User $user, bool $isAllAccess): bool
{
if ($this->hasAccess($documentBailiff, $user, $isAllAccess) === true) {
return DocumentBailiffStatusEnum::SENT === $documentBailiff->getStatus() ||
DocumentBailiffStatusEnum::RECEIVED === $documentBailiff->getStatus();
}
return false;
}
/**
* @param DocumentBailiff $documentBailiff
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canCancel(DocumentBailiff $documentBailiff, User $user, bool $isAllAccess): bool
{
if ($this->hasAccess($documentBailiff, $user, $isAllAccess) === true) {
return DocumentBailiffStatusEnum::SENT === $documentBailiff->getStatus() ||
DocumentBailiffStatusEnum::RECEIVED === $documentBailiff->getStatus() ||
DocumentBailiffStatusEnum::SUSPENDED === $documentBailiff->getStatus();
}
return false;
}
/**
* @param DocumentBailiff $documentBailiff
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canResume(DocumentBailiff $documentBailiff, User $user, bool $isAllAccess): bool
{
if ($this->hasAccess($documentBailiff, $user, $isAllAccess) === true) {
return DocumentBailiffStatusEnum::SUSPENDED === $documentBailiff->getStatus();
}
return false;
}
/**
* @param DocumentBailiff $documentBailiff
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canAccessDriveFile(DocumentBailiff $documentBailiff, User $user, bool $isAllAccess): bool
{
if ($this->hasAccess($documentBailiff, $user, $isAllAccess) === true) {
return $this->canView($documentBailiff, $user, $isAllAccess) && DocumentBailiffStatusEnum::SERVED === $documentBailiff->getStatus();
}
return false;
}
/**
* @param DocumentBailiff $documentBailiff
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canDownloadDriveFile(DocumentBailiff $documentBailiff, User $user, bool $isAllAccess): bool
{
if ($this->hasAccess($documentBailiff, $user, $isAllAccess) === true) {
return $this->canView($documentBailiff, $user, $isAllAccess) && DocumentBailiffStatusEnum::SERVED === $documentBailiff->getStatus();
}
return false;
}
/**
* @param DocumentBailiff $documentBailiff
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canView(DocumentBailiff $documentBailiff, User $user, bool $isAllAccess): bool
{
return $this->hasAccess($documentBailiff, $user, $isAllAccess);
}
/**
* @param DocumentBailiff $documentBailiff
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function hasAccess(DocumentBailiff $documentBailiff, User $user, bool $isAllAccess): bool
{
if (false === $isAllAccess) {
return (int) $user->getId() === (int) $documentBailiff->getUser()->getId();
}
return true;
}
}