<?php
/**
* This file is part of the educat package.
*
* (c) Solvee
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace App\Task\Application\Security;
use App\Common\MentorApplicants\MentorApplicantsProviderInterface;
use App\Common\Model\Core\AccountInterface;
use App\Common\Model\Core\UserInterface;
use App\Common\Model\Task\TaskInterface;
use App\Common\Security\ObjectOwnerVoterInterface;
use App\Common\Security\ObjectOwnerVoterTrait;
use App\Common\Security\VoterTrait;
use App\ContentFile\Application\Security\ContentFileVoter;
use LogicException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
use function in_array;
/**
* Class TaskVoter
*
* @author Kamil KozaczyĆski <kozaczynski.kamil@gmail.com>
*/
class TaskVoter extends Voter implements ObjectOwnerVoterInterface
{
public const CREATE_TASK = 'create_task';
use VoterTrait, ObjectOwnerVoterTrait;
/** @var MentorApplicantsProviderInterface */
private MentorApplicantsProviderInterface $mentorApplicantsProvider;
/**
* @param Security $security
* @param MentorApplicantsProviderInterface $mentorApplicantsProvider
*/
public function __construct(
Security $security,
MentorApplicantsProviderInterface $mentorApplicantsProvider
) {
$this->security = $security;
$this->mentorApplicantsProvider = $mentorApplicantsProvider;
}
/**
* @inheritDoc
*/
protected function supports(string $attribute, $subject): bool
{
if (!in_array(
$attribute,
[
self::OBJECT_OWNER,
self::CREATE_TASK,
],
true
)) {
return false;
}
return $subject instanceof TaskInterface;
}
/**
* @param string $attribute
* @param TaskInterface $subject
* @param TokenInterface $token
*
* @return bool
*/
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return false;
}
return match ($attribute) {
self::OBJECT_OWNER => $this->isObjectOwner($subject, $user->getAccount()),
self::CREATE_TASK => $this->canCreateTask($subject, $user->getAccount()),
default => throw new LogicException('This code should not be reached.')
};
}
/**
* @param TaskInterface $task
* @param AccountInterface $account
*
* @return bool
*/
private function canCreateTask(TaskInterface $task, AccountInterface $account): bool
{
if ($this->isAdmin()) {
return true;
}
if ($task->getMentor() &&
!$this->mentorApplicantsProvider->doesApplicantBelongToMentor($task->getApplicant(), $task->getMentor())) {
return false;
}
if (!$this->isObjectOwner($task, $account)) {
return false;
}
foreach ($task->getContentFiles() as $contentFile) {
if (!$this->security->isGranted(ContentFileVoter::CAN_ACCESS, $contentFile)) {
return false;
}
}
return true;
}
}