<?php
declare(strict_types=1);
namespace App\Security\Voter\Profile;
use App\Model\User\Entity\User\Role\Permission;
use App\Model\User\Entity\User\Role\RoleConstants;
use App\ReadModel\Profile\DetailView;
use App\Security\UserIdentity;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
class ProfileVoter extends Voter
{
public const PROFILE_CREATE = 'profile_create';
public const PROFILE_EDIT = 'profile_edit';
public const PROFILE_INDEX = 'profile_index';
public const PROFILE_RECALL = 'profile_recall';
public const ORGANIZATION_USERS_LIST = 'organization_users_list';
public const ORGANIZATION_POSITION_LIST = 'organization_position_list';
public const ORGANIZATION_USERS_CREATE = 'organization_users_create';
public const ORGANIZATION_USERS_DELETE = 'organization_users_delete';
public const CONTRACTS_LIST = 'contracts_list';
public const PROCEDURE_MY_LIST = 'procedure_my_list';
private Security $security;
public function __construct(Security $security)
{
$this->security = $security;
}
protected function supports(string $attribute, $subject): bool
{
return in_array($attribute, [
self::PROFILE_CREATE,
self::PROFILE_EDIT,
self::PROFILE_INDEX,
self::PROFILE_RECALL,
self::ORGANIZATION_USERS_LIST,
self::ORGANIZATION_POSITION_LIST,
self::ORGANIZATION_USERS_CREATE,
self::ORGANIZATION_USERS_DELETE,
self::CONTRACTS_LIST,
self::PROCEDURE_MY_LIST
], true);
}
/**
* @param string $attribute
* @param $subject
* @param TokenInterface $token
* @return bool
*/
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
// Moderators have full access
if ($this->security->isGranted('ROLE_MODERATOR')) {
return true;
}
$user = $token->getUser();
// Only authenticated UserIdentity can proceed
if (!$user instanceof UserIdentity) {
return false;
}
$role = (new RoleConstants($user->getRole()));
if ($role->isOrganizerUser()) {
if ($this->checkPermissionEmployee($user, $attribute, $subject) === false) {
return $this->handleException();
}
}
// Check specific permissions
switch ($attribute) {
case self::PROFILE_INDEX:
if (!$this->isOwnerProfile($subject, $user)) {
return $this->handleException();
}
break;
case self::PROFILE_EDIT:
// Only profile owner can proceed
if (!$this->isOwnerProfile($subject, $user)) {
return $this->handleException();
}
return $user->isPermission(Permission::PROFILE_EDIT);
break;
case self::CONTRACTS_LIST:
// Only profile owner can proceed
if (!$this->isOwnerProfile($subject, $user)) {
return $this->handleException();
}
return $user->isPermission(Permission::CONTRACTS_LIST);
break;
case self::PROCEDURE_MY_LIST:
if ($subject->id !== $user->getProfileId()) {
return $this->handleException();
}
break;
}
return true;
}
private function handleException()
{
throw new AccessDeniedException('Доступ запрещен. У вас недостаточно прав для совершения этого действия.');
}
/**
* Проверка разрешений сотрудника
* @param UserIdentity $user
* @param string $attribute
* @param DetailView $subject
* @return bool
*/
private function checkPermissionEmployee(UserIdentity $user, string $attribute, DetailView $subject): bool
{
switch ($attribute) {
case self::PROFILE_INDEX:
if (!$this->isOwnerProfile($subject, $user)) {
return false;
}
return true;
break;
case self::PROFILE_EDIT:
if (!$this->isOwnerProfile($subject, $user)) {
return false;
}
return $user->isPermission(Permission::PROFILE_EDIT);
break;
case self::ORGANIZATION_USERS_LIST:
// Only profile owner can proceed
if (!$this->isOwnerProfile($subject, $user)) {
return false;
}
return $user->isPermission(Permission::ORGANIZATION_USERS_LIST);
break;
case self::ORGANIZATION_POSITION_LIST:
if (!$this->isOwnerProfile($subject, $user)) {
return false;
}
return $user->isPermission(Permission::ORGANIZATION_POSITION_LIST);
break;
case self::ORGANIZATION_USERS_CREATE:
if (!$this->isOwnerProfile($subject, $user)) {
return false;
}
return $user->isPermission(Permission::ORGANIZATION_USERS_CREATE);
break;
case self::ORGANIZATION_USERS_DELETE:
if (!$this->isOwnerProfile($subject, $user)) {
return false;
}
return $user->isPermission(Permission::ORGANIZATION_USERS_DELETE);
break;
case self::CONTRACTS_LIST:
if (!$this->isOwnerProfile($subject, $user)) {
return false;
}
return $user->isPermission(Permission::CONTRACTS_LIST);
break;
case self::PROCEDURE_MY_LIST:
if ($subject->id !== $user->getProfileId()) {
return $this->handleException();
}
return true;
break;
default:
return false;
}
}
private function isOwnerProfile(DetailView $subject, UserIdentity $user): bool
{
// Only profile owner can proceed
if ($subject->id !== $user->getProfileId()) {
return false;
}
return true;
}
}