<?php
namespace MedBrief\MSR\Security\Voter;
use MedBrief\MSR\Entity\Account;
use MedBrief\MSR\Entity\Firm;
use MedBrief\MSR\Entity\User;
use Override;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;
class AccountVoter extends Voter
{
public const CREATE = 'CREATE';
public const READ = 'READ';
public const UPDATE = 'UPDATE';
public const DELETE = 'DELETE';
public const ADMINISTRATION = 'ADMINISTRATION';
public const USER_ADMINISTRATION = 'USER_ADMINISTRATION';
public const SORTING_SETTINGS_ADMINISTRATION = 'SORTING_SETTINGS_ADMINISTRATION';
public const MATTER_REQUEST_DEFAULTS_ADMINISTRATION = 'MATTER_REQUEST_DEFAULTS_ADMINISTRATION';
public const INDEX_HEADER_ADMINISTRATION = 'INDEX_HEADER_ADMINISTRATION';
public const TECHNICAL_ADMINISTRATION = 'TECHNICAL_ADMINISTRATION';
public const UPDATE_PHYSICAL_ADDRESS = 'UPDATE_PHYSICAL_ADDRESS';
public const ADD_OFFICE = 'ADD_OFFICE';
public const ADD_MATTER_REQUEST = 'ADD_MATTER_REQUEST';
public const ADD_LICENCE_RENEWAL_TERM = 'ADD_LICENCE_RENEWAL_TERM';
public const ACCESS_GRANTED = true;
public const ACCESS_DENIED = false;
public function __construct(private readonly AuthorizationCheckerInterface $authorizationChecker)
{
}
#[Override]
protected function supports($attribute, $subject)
{
return in_array($attribute, [
self::CREATE,
self::READ,
self::UPDATE,
self::DELETE,
self::ADMINISTRATION,
self::USER_ADMINISTRATION,
self::SORTING_SETTINGS_ADMINISTRATION,
self::MATTER_REQUEST_DEFAULTS_ADMINISTRATION,
self::INDEX_HEADER_ADMINISTRATION,
self::UPDATE_PHYSICAL_ADDRESS,
self::ADD_OFFICE,
self::TECHNICAL_ADMINISTRATION,
self::ADD_MATTER_REQUEST,
self::ADD_LICENCE_RENEWAL_TERM,
])
&& ($subject instanceof Account || is_subclass_of($subject, Account::class));
}
#[Override]
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
// if the user is anonymous, do not grant access
if (!$user instanceof UserInterface) {
return self::ACCESS_DENIED;
}
if ($user instanceof Firm && $user->getClientAreas()->contains($subject)) {
return self::ACCESS_GRANTED;
}
// Super Admin and Admin users can add/edit terms
if ($attribute === self::ADD_LICENCE_RENEWAL_TERM) {
return $this->canCreate();
}
// Super Admin users can do everything
if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) {
return self::ACCESS_GRANTED;
}
switch ($attribute) {
case self::CREATE:
case self::DELETE:
case self::ADMINISTRATION:
case self::SORTING_SETTINGS_ADMINISTRATION:
case self::MATTER_REQUEST_DEFAULTS_ADMINISTRATION:
// Only Super Admins may create, delete Accounts or have full administration rights
return self::ACCESS_DENIED;
case self::UPDATE:
// If not an internal user, deny updating
return $user->isUserTypeInternal();
}
// If this user is a Client Super Administrator for the Account then they can
// do everything else
if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $subject->getId() . '_SUPERADMINISTRATOR')) {
return self::ACCESS_GRANTED;
}
// Otherwise if this user is a Client Administrator for the Account then they can
// do everything else except for User Administration and Technical Admin
if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $subject->getId() . '_ADMINISTRATOR') && !in_array($attribute, [
self::USER_ADMINISTRATION,
self::TECHNICAL_ADMINISTRATION,
])) {
return self::ACCESS_GRANTED;
}
// A Client technical administrator may perform technical administration as well as other duties
if ($this->authorizationChecker->isGranted('ROLE_ACCOUNT_' . $subject->getId() . '_TECHNICAL_ADMIN') && in_array($attribute, [
self::READ,
self::TECHNICAL_ADMINISTRATION,
self::ADD_MATTER_REQUEST,
])) {
return self::ACCESS_GRANTED;
}
return self::ACCESS_DENIED;
}
private function canCreate(): bool
{
return $this->authorizationChecker->isGranted('ROLE_ADMIN');
}
}