<?php
namespace App\DocumentWorkflow\Security;
use App\DocumentWorkflow\Entity\DocumentWorkflow;
use App\DocumentWorkflow\Enum\DocumentWorkflowStatusEnum;
use App\DocumentWorkflow\Repository\DocumentWorkflowStepRepository;
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 DocumentWorkflowVoter
*/
class DocumentWorkflowVoter extends Voter
{
public const COMMENT = 'comment';
public const DELETE = 'delete';
public const DOWNLOAD_DRIVE_FILE = 'download_drive_file';
public const EDIT = 'edit';
public const REVISE = 'revise';
public const SEE_REVISE_BUTTON_IN_VIEW = 'see_revise_button_in_view';
public const SEE_VALIDATE_BUTTON_IN_VIEW = 'see_validate_button_in_view';
public const VALIDATE = 'validate';
public const VIEW = 'view';
/**
* @var DocumentWorkflowStepRepository
*/
private $documentWorkflowStepRepository;
/**
* @var AccessDecisionManagerInterface
*/
private $decisionManager;
/**
* DocumentWorkflowVoter constructor.
* @param DocumentWorkflowStepRepository $documentWorkflowStepRepository
* @param AccessDecisionManagerInterface $decisionManager
*/
public function __construct(
DocumentWorkflowStepRepository $documentWorkflowStepRepository,
AccessDecisionManagerInterface $decisionManager
) {
$this->documentWorkflowStepRepository = $documentWorkflowStepRepository;
$this->decisionManager = $decisionManager;
}
/**
* {@inheritdoc}
*/
protected function supports($attribute, $subject): bool
{
if (!in_array(
$attribute,
[
self::COMMENT,
self::DELETE,
self::DOWNLOAD_DRIVE_FILE,
self::EDIT,
self::REVISE,
self::SEE_REVISE_BUTTON_IN_VIEW,
self::SEE_VALIDATE_BUTTON_IN_VIEW,
self::VALIDATE,
self::VIEW,
]
)) {
return false;
}
if (!$subject instanceof DocumentWorkflow) {
return false;
}
return true;
}
/**
* {@inheritdoc}
* @param DocumentWorkflow $documentWorkflow
*/
protected function voteOnAttribute($attribute, $documentWorkflow, TokenInterface $token)
{
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
if (!$user->getLawFirm()->hasModule(ModuleEnum::MODULE_DOCUMENT_WORKFLOW)) {
return false;
}
$isAllAccess = $this->decisionManager->decide($token, [FeatureAccessEnum::ALL_DOCUMENT_WORKFLOWS_ACCESS]);
switch ($attribute) {
case self::DELETE:
case self::EDIT:
return $this->canEdit($documentWorkflow, $user, $isAllAccess);
case self::VIEW:
case self::COMMENT:
return $this->canView($documentWorkflow, $user, $isAllAccess);
case self::DOWNLOAD_DRIVE_FILE:
return $this->canDownloadDriveFile($documentWorkflow, $user, $isAllAccess);
case self::REVISE:
return $this->canRevise($documentWorkflow, $user);
case self::VALIDATE:
return $this->canValidate($documentWorkflow, $user);
case self::SEE_VALIDATE_BUTTON_IN_VIEW:
return $this->canSeeValidateButtonInView($documentWorkflow, $user);
case self::SEE_REVISE_BUTTON_IN_VIEW:
return $this->canSeeReviseButtonInView($documentWorkflow, $user);
default:
throw new InvalidArgumentException('Invalid attribute');
}
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @return bool
*/
private function canSeeReviseButtonInView(DocumentWorkflow $documentWorkflow, User $user): bool
{
if (DocumentWorkflowStatusEnum::VALIDATED === $documentWorkflow->getStatus()) {
return false;
}
// Si le user est participant, hors créateur
if (count($this->documentWorkflowStepRepository->findByDocumentWorkflowAndUserWithoutCreator($documentWorkflow, $user)) < 1) {
return false;
}
return true;
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @return bool
*/
private function canSeeValidateButtonInView(DocumentWorkflow $documentWorkflow, User $user): bool
{
if (DocumentWorkflowStatusEnum::VALIDATED === $documentWorkflow->getStatus()) {
return false;
}
// Si le user est participant, créateur compris
if (count($this->documentWorkflowStepRepository->findByDocumentWorkflowAndUser($documentWorkflow, $user)) < 1) {
return false;
}
return true;
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @return bool
*/
private function canRevise(DocumentWorkflow $documentWorkflow, User $user): bool
{
if (!$this->canValidate($documentWorkflow, $user)) {
return false;
}
return !$documentWorkflow->getCurrentStep()->isCreator();
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @return bool
*/
private function canValidate(DocumentWorkflow $documentWorkflow, User $user): bool
{
if (null === $documentWorkflow->getCurrentStep()) {
return false;
}
return $documentWorkflow->getCurrentStep()->getUser()->getId() === $user->getId();
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canDownloadDriveFile(DocumentWorkflow $documentWorkflow, User $user, bool $isAllAccess): bool
{
return $this->canView($documentWorkflow, $user, $isAllAccess) && DocumentWorkflowStatusEnum::VALIDATED === $documentWorkflow->getStatus();
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canView(DocumentWorkflow $documentWorkflow, User $user, bool $isAllAccess): bool
{
if (true === $isAllAccess) {
return true;
}
if (!$this->canEdit($documentWorkflow, $user, $isAllAccess)) {
$userSteps = $this->documentWorkflowStepRepository->findByDocumentWorkflowAndUser($documentWorkflow, $user);
if (count($userSteps) < 1) {
return false;
}
}
return true;
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @param bool $isAllAccess
* @return bool
*/
private function canEdit(DocumentWorkflow $documentWorkflow, User $user, bool $isAllAccess): bool
{
return ($isAllAccess || $this->isCreator($documentWorkflow, $user))
&& $documentWorkflow->getStatus() !== DocumentWorkflowStatusEnum::VALIDATED;
}
/**
* @param DocumentWorkflow $documentWorkflow
* @param User $user
* @return bool
*/
private function isCreator(DocumentWorkflow $documentWorkflow, User $user): bool
{
return $user->getId() === $documentWorkflow->getUser()->getId();
}
}