<?php
declare(strict_types=1);
namespace MedBrief\MSR\Security\Voter;
use InvalidArgumentException;
use MedBrief\MSR\Entity\Account;
use MedBrief\MSR\Entity\Project;
use MedBrief\MSR\Entity\RoleInvitation;
use MedBrief\MSR\Entity\User;
use MedBrief\MSR\Service\Role\RoleParserService;
use Override;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
final class RoleInvitationVoter implements VoterInterface
{
public const REMIND = 'REMIND_ROLE_INVITATION';
public function __construct(
private readonly AuthorizationCheckerInterface $authorizationChecker,
private readonly RoleParserService $roleParser
) {
}
public function supportsAttribute($attribute): bool
{
return self::REMIND === $attribute;
}
public function supportsClass($class): bool
{
return RoleInvitation::class === $class || is_subclass_of($class, RoleInvitation::class);
}
#[Override]
public function vote(TokenInterface $token, $subject, array $attributes): int
{
if (!$subject instanceof RoleInvitation) {
return self::ACCESS_ABSTAIN;
}
if (1 !== count($attributes)) {
throw new InvalidArgumentException('Only one attribute is allowed for MedBrief voters.');
}
if (!$this->supportsAttribute($attributes[0])) {
return self::ACCESS_ABSTAIN;
}
if (!$token->getUser() instanceof User) {
return self::ACCESS_DENIED;
}
if ($this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN')
|| $this->authorizationChecker->isGranted('ROLE_ADMIN')) {
return self::ACCESS_GRANTED;
}
$parsedRole = $this->roleParser->parseRole($subject->getRole());
if (false === $parsedRole) {
return self::ACCESS_DENIED;
}
$roleSubject = $parsedRole->getSubject();
if ($roleSubject instanceof Account
&& $this->authorizationChecker->isGranted('USER_ADMINISTRATION', $roleSubject)) {
return self::ACCESS_GRANTED;
}
if ($roleSubject instanceof Project
&& ($this->authorizationChecker->isGranted('USER_ADMINISTRATION', $roleSubject)
|| $this->authorizationChecker->isGranted('MEDICAL_RECORDS_ADMINISTRATION', $roleSubject))) {
return self::ACCESS_GRANTED;
}
return self::ACCESS_DENIED;
}
}