<?php
namespace App\Security;
use App\Entity\Company;
use App\Entity\Location;
use App\Entity\Role;
use App\Entity\User;
use App\Entity\UserLocation;
use App\Enum\User\UserRestrictionsEnum;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
class UserVoter extends Voter
{
/** @var Security */
private $security;
/** @var RequestStack */
private $requestStack;
public function __construct(Security $security, RequestStack $requestStack)
{
$this->security = $security;
$this->requestStack = $requestStack;
}
public const CAN_ACCESS_BILLING_DATA = 'CAN_ACCESS_BILLING_DATA';
public const CAN_ACCESS_COMPANIES_LOCATIONS = 'CAN_ACCESS_COMPANIES_LOCATIONS';
public const CAN_ACCESS_USERS = 'CAN_ACCESS_USERS';
public const CAN_GRANT_HATCH_ADMIN = 'CAN_GRANT_HATCH_ADMIN';
public const CAN_SWITCH_USER = 'CAN_SWITCH_USER';
public const HAS_ADMIN_ACCESS_NO_RESTRICTIONS = 'HAS_ADMIN_ACCESS_NO_RESTRICTIONS';
public const USER_HAS_ROLE_HUMAN_RESOURCES = 'user_has_role_human_resources';
public const VIEW_USERS_TRAININGS_AND_QUIZZES = 'VIEW_USERS_TRAININGS_AND_QUIZZES';
protected function supports($attribute, $subject): bool
{
return in_array($attribute, [
self::CAN_ACCESS_BILLING_DATA,
self::CAN_ACCESS_COMPANIES_LOCATIONS,
self::CAN_ACCESS_USERS,
self::CAN_GRANT_HATCH_ADMIN,
self::CAN_SWITCH_USER,
self::HAS_ADMIN_ACCESS_NO_RESTRICTIONS,
self::USER_HAS_ROLE_HUMAN_RESOURCES,
self::VIEW_USERS_TRAININGS_AND_QUIZZES,
], true);
}
/**
* @param $attribute
* @param $subject
* @param TokenInterface $token
* @return bool
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
if ($attribute === self::CAN_GRANT_HATCH_ADMIN) {
return in_array(strtolower($user->getUsername()) , ['megenos', 'crivera305']);
}
if ($attribute === self::USER_HAS_ROLE_HUMAN_RESOURCES && $subject instanceof Location) {
return $user->hasRoleByCompany(Role::ROLE_NAME_HUMAN_RESOURCES, $subject->getCompany());
}
if ($attribute === self::CAN_SWITCH_USER) {
return $this->handleImpersonation($user, $subject);
}
// at this point $attribute is VIEW_USERS_TRAININGS_AND_QUIZZES
if ($attribute === self::VIEW_USERS_TRAININGS_AND_QUIZZES) {
return $this->handleViewUsersTrainingsAndQuizzes($user, $subject);
}
if ($attribute === self::HAS_ADMIN_ACCESS_NO_RESTRICTIONS) {
return $user->isHatchAdministrator() && !$user->hasRestrictions();
}
if ($attribute === self::CAN_ACCESS_COMPANIES_LOCATIONS) {
return $user->isHatchAdministrator()
&& $user->hasRestriction(UserRestrictionsEnum::USER_RESTRICTION_COMPANIES_LOCATIONS);
}
if ($attribute === self::CAN_ACCESS_BILLING_DATA) {
return $user->isHatchAdministrator()
&& $user->hasRestriction(UserRestrictionsEnum::USER_RESTRICTION_BILLING_DATA);
}
if ($attribute === self::CAN_ACCESS_USERS) {
return $user->isHatchAdministrator()
&& $user->hasRestriction(UserRestrictionsEnum::USER_RESTRICTION_USERS);
}
return false;
}
/**
* @param User $user
* @param $subject
* @return bool
*/
protected function handleImpersonation(User $user, $subject): bool
{
if ($this->security->isGranted('ROLE_ADMIN')) {
return true;
} else {
$request = $this->requestStack->getCurrentRequest();
$routeParameters = $request->attributes->get('_route_params');
if (isset($routeParameters['company'])) {
$companies = $user->getCompanies();
foreach ($companies as $company) {
if ($routeParameters['company'] == $company->getId()){
return $user->hasRoleByCompany(Role::ROLE_NAME_HUMAN_RESOURCES, $company);
}
}
}
if ($subject instanceof Company) {
return $user->hasRoleByCompany(Role::ROLE_NAME_HUMAN_RESOURCES, $subject);
}
if (!$subject instanceof Location) {
$userLocations = $user->getUserLocations();
/** @var UserLocation $userLocation */
foreach ($userLocations as $userLocation) {
$location = $userLocation->getLocation();
if (!isset($_REQUEST['locationId'])) {
if ($location->isActive()) {
$subject = $location;
break;
}
} else if ($location->getId() == (int)$_REQUEST['locationId']) {
$subject = $location;
break;
}
}
}
if ($subject instanceof Location) {
return $user->hasRoleByCompany(Role::ROLE_NAME_HUMAN_RESOURCES, $subject->getCompany());
}
return false;
}
}
/**
* @param User $user
* @param $subject
* @return bool
*/
private function handleViewUsersTrainingsAndQuizzes(User $user, $subject): bool
{
if (!$subject instanceof Location) {
return false;
}
//ANY ATTRIBUTE that makes it to here will return false if the condition below is met
if (
!$user->isAdminByCompany($subject->getCompany()) &&
!$user->isSupervisorByCompany($subject->getCompany()) &&
!$user->hasRoleByCompany(Role::ROLE_NAME_TJC_SURVEYOR, $subject->getCompany()) &&
!$user->hasRoleByCompany(Role::ROLE_NAME_STATE_INSPECTOR, $subject->getCompany()) &&
!$user->hasRoleByCompany(Role::ROLE_NAME_HUMAN_RESOURCES, $subject->getCompany())
) {
return false;
}
return true;
}
}