mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-24 15:44:59 +00:00
This commit adjusts the conditions in CalendarVoter and ActivityVoter security checks. Now it takes into account both STEP_DRAFT and STEP_CLOSED statuses in determining permissions. This enhancement ensures tighter control over specific actions in these two scenarios, enhancing the overall application security.
168 lines
5.7 KiB
PHP
168 lines
5.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Chill\ActivityBundle\Security\Authorization;
|
|
|
|
use Chill\ActivityBundle\Entity\Activity;
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
|
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
|
|
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
|
|
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|
use Chill\PersonBundle\Entity\Person;
|
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
|
use Symfony\Component\Security\Core\Security;
|
|
|
|
class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
|
{
|
|
/**
|
|
* allow to create an activity, which will either be associated to an
|
|
* accompanying course or person.
|
|
*
|
|
* It is safe for usage in template and controller
|
|
*/
|
|
final public const CREATE = 'CHILL_ACTIVITY_CREATE';
|
|
|
|
/**
|
|
* role to allow to create an activity associated win an accompanying course.
|
|
*
|
|
* Before using this, check if @see{self::CREATE} is not sufficiant
|
|
*
|
|
* @internal
|
|
*/
|
|
final public const CREATE_ACCOMPANYING_COURSE = 'CHILL_ACTIVITY_CREATE_ACCOMPANYING_COURSE';
|
|
|
|
/**
|
|
* role to allow to create an activity associated with a person.
|
|
*
|
|
* Before using this, check if @see{self::CREATE} is not sufficiant
|
|
*
|
|
* @internal
|
|
*/
|
|
final public const CREATE_PERSON = 'CHILL_ACTIVITY_CREATE_PERSON';
|
|
|
|
final public const DELETE = 'CHILL_ACTIVITY_DELETE';
|
|
|
|
final public const FULL = 'CHILL_ACTIVITY_FULL';
|
|
|
|
final public const SEE = 'CHILL_ACTIVITY_SEE';
|
|
|
|
final public const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS';
|
|
|
|
final public const UPDATE = 'CHILL_ACTIVITY_UPDATE';
|
|
|
|
private const ALL = [
|
|
self::CREATE,
|
|
self::SEE,
|
|
self::UPDATE,
|
|
self::DELETE,
|
|
self::SEE_DETAILS,
|
|
self::FULL,
|
|
];
|
|
|
|
protected VoterHelperInterface $voterHelper;
|
|
|
|
public function __construct(
|
|
protected Security $security,
|
|
VoterHelperFactoryInterface $voterHelperFactory
|
|
) {
|
|
$this->voterHelper = $voterHelperFactory->generate(self::class)
|
|
->addCheckFor(Person::class, [self::SEE, self::CREATE])
|
|
->addCheckFor(AccompanyingPeriod::class, [self::SEE, self::CREATE])
|
|
->addCheckFor(Activity::class, self::ALL)
|
|
->build();
|
|
}
|
|
|
|
public function getRoles(): array
|
|
{
|
|
return [
|
|
self::SEE,
|
|
self::SEE_DETAILS,
|
|
self::CREATE_PERSON,
|
|
self::CREATE_ACCOMPANYING_COURSE,
|
|
self::UPDATE,
|
|
self::DELETE,
|
|
self::FULL,
|
|
];
|
|
}
|
|
|
|
public function getRolesWithHierarchy(): array
|
|
{
|
|
return ['Activity' => $this->getRoles()];
|
|
}
|
|
|
|
public function getRolesWithoutScope(): array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
protected function supports($attribute, $subject): bool
|
|
{
|
|
return $this->voterHelper->supports($attribute, $subject);
|
|
}
|
|
|
|
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
|
|
{
|
|
if (!$token->getUser() instanceof User) {
|
|
return false;
|
|
}
|
|
|
|
if ($subject instanceof Activity) {
|
|
if ($subject->getPerson() instanceof Person) {
|
|
// the context is person: we must have the right to see the person
|
|
if (!$this->security->isGranted(PersonVoter::SEE, $subject->getPerson())) {
|
|
return false;
|
|
}
|
|
|
|
// change attribute CREATE
|
|
if (self::CREATE === $attribute) {
|
|
return $this->voterHelper->voteOnAttribute(self::CREATE_PERSON, $subject->getPerson(), $token);
|
|
}
|
|
} elseif ($subject->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
|
|
if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getAccompanyingPeriod())) {
|
|
return false;
|
|
}
|
|
|
|
if (self::CREATE === $attribute) {
|
|
if (AccompanyingPeriod::STEP_CLOSED === $subject->getAccompanyingPeriod()->getStep()) {
|
|
return false;
|
|
}
|
|
|
|
return $this->voterHelper->voteOnAttribute(self::CREATE_ACCOMPANYING_COURSE, $subject->getAccompanyingPeriod(), $token);
|
|
}
|
|
} else {
|
|
throw new \RuntimeException('Could not determine context of activity.');
|
|
}
|
|
} elseif ($subject instanceof AccompanyingPeriod) {
|
|
if (AccompanyingPeriod::STEP_CLOSED === $subject->getStep() || AccompanyingPeriod::STEP_DRAFT === $subject->getStep()) {
|
|
if (\in_array($attribute, [self::UPDATE, self::CREATE, self::DELETE], true)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// transform the attribute
|
|
if (self::CREATE === $attribute) {
|
|
return $this->voterHelper->voteOnAttribute(self::CREATE_ACCOMPANYING_COURSE, $subject, $token);
|
|
}
|
|
} elseif ($subject instanceof Person) {
|
|
// transform the attribute
|
|
if (self::CREATE === $attribute) {
|
|
return $this->voterHelper->voteOnAttribute(self::CREATE_PERSON, $subject, $token);
|
|
}
|
|
}
|
|
|
|
return $this->voterHelper->voteOnAttribute($attribute, $subject, $token);
|
|
}
|
|
}
|