<?php
namespace App\Security\Voter;
use App\Entity\MeetingPoll;
use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
/**
* Permissions sur un {@see MeetingPoll} :
* - VIEW : tous les membres du workroom (délégué à WorkroomVoter::WORKROOM_VIEW)
* - VOTE : idem VIEW + sondage non clos
* - EDIT : owner uniquement (titre, description, deadline, options)
* - DELETE : owner uniquement
* - FINALIZE : owner uniquement
*
* Délégation : VIEW vérifie l'appartenance au workroom via le voter existant
* `WorkroomVoter` plutôt que de dupliquer la logique de membership.
*/
class MeetingPollVoter extends Voter
{
public const POLL_VIEW = 'meeting_poll_view';
public const POLL_VOTE = 'meeting_poll_vote';
public const POLL_EDIT = 'meeting_poll_edit';
public const POLL_DELETE = 'meeting_poll_delete';
public const POLL_FINALIZE = 'meeting_poll_finalize';
public function __construct(
private readonly AccessDecisionManagerInterface $decisionManager,
) {}
protected function supports($attribute, $subject): bool
{
return $subject instanceof MeetingPoll && in_array($attribute, [
self::POLL_VIEW,
self::POLL_VOTE,
self::POLL_EDIT,
self::POLL_DELETE,
self::POLL_FINALIZE,
], true);
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof User) return false;
/** @var MeetingPoll $poll */
$poll = $subject;
$workroom = $poll->getWorkroom();
if (!$workroom) return false;
// VIEW = membre du workroom (délégué au voter workroom)
$isMember = $this->decisionManager->decide($token, [WorkroomVoter::WORKROOM_VIEW], $workroom);
if (!$isMember) return false;
switch ($attribute) {
case self::POLL_VIEW:
return true;
case self::POLL_VOTE:
// Voter requis : sondage non clos. Si une deadline est passée
// on accepte quand même tant que !isClosed (la deadline est
// informative ; l'organisateur ferme manuellement).
return !$poll->isClosed();
case self::POLL_EDIT:
case self::POLL_DELETE:
case self::POLL_FINALIZE:
return $poll->getOwner()?->getId() === $user->getId();
}
return false;
}
}