<?php
namespace App\EspaceDocBundle\Security;
use App\Entity\Contacts;
use App\Entity\User;
use App\EspaceDocBundle\Entity\Acl;
use App\EspaceDocBundle\Entity\Category;
use App\EspaceDocBundle\Entity\Document;
use App\EspaceDocBundle\Entity\UserGroup;
use App\EspaceDocBundle\Repository\AclRepository;
use App\EspaceDocBundle\Repository\DocumentRepository;
use App\EspaceDocBundle\Repository\UserGroupRepository;
use App\Repository\ContactsRepository;
use Doctrine\ORM\EntityManager;
use PhpParser\Comment\Doc;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class CategoryVoter extends Voter implements ContainerAwareInterface
{
const VIEW = 'view';
const EDIT = 'edit';
const DELETE = 'delete';
const EDIT_DOCUMENTS = 'edit_documents';
const EDIT_DOCUMENTS_LIKE = 'edit_documents_like';
const VIEW_DOCUMENTS_LIKE = 'view_documents_like';
const BULK_DELETE_DOCUMENTS_POST = 'bulk_delete_documents_post';
private $container;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var EntityManager L'EM de l'ED
*/
private $edEntityManager;
/**
* @var EntityManager L'EM du site
*/
private $entityManager;
public function setContainer(ContainerInterface $container = null)
{
$this->setContainer($container);
}
public function __construct(RequestStack $requestStack, LoggerInterface $logger, ContainerInterface $container)
{
$this->container = $container;
$this->logger = $logger;
$this->requestStack = $requestStack;
$doctrine = $this->container->get('doctrine');
$this->edEntityManager = $doctrine->getManager('espacedoc');
$this->entityManager = $doctrine->getManager();
}
protected function supports($attribute, $subject)
{
// Voter seulement sur ce qui me concerne
if(!in_array($attribute, [
self::VIEW,
self::EDIT,
self::DELETE,
self::EDIT_DOCUMENTS,
self::EDIT_DOCUMENTS_LIKE,
self::VIEW_DOCUMENTS_LIKE,
self::BULK_DELETE_DOCUMENTS_POST,
])) {
return false;
}
if(
!$subject instanceof Category && // Si on ne me donne pas une catégorie
!($subject instanceof Document && ( // Ni un document
$attribute === self::EDIT_DOCUMENTS_LIKE ||
$attribute === self::VIEW_DOCUMENTS_LIKE ||
$attribute === self::VIEW
)) && (
$attribute !== self::BULK_DELETE_DOCUMENTS_POST // S'il ne s'agit pas d'un bulk delete (dans ce cas, le subjectest dans $_POST
)
) {
return false;
}
return true;
}
/**
* @param string $attribute
* @param mixed $subject
* @param TokenInterface $token
* @return bool
* @throws \Doctrine\ORM\NonUniqueResultException
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$user = $token->getUser();
if($attribute !== self::EDIT_DOCUMENTS_LIKE) {
/** @var Category $category */
$category = $subject;
} else {
/** @var Document $document */
$document = $subject;
}
// Si utilisateur pas connecté, dehors
if (!$user instanceof User) {
return false;
}
// Superadmin peut tout faire
if($user->getIsSuper()) {
return true;
}
switch ($attribute) {
case self::VIEW:
return $this->canView($category, $user);
case self::EDIT:
return $this->canEdit($category, $user);
case self::EDIT_DOCUMENTS:
return $this->canEditDocuments($category, $user);
case self::EDIT_DOCUMENTS_LIKE:
return $this->canEditDocuments($document->getCategory(), $user);
case self::VIEW_DOCUMENTS_LIKE:
return $this->canViewDocuments($document->getCategory(), $user);
case self::DELETE:
return $this->canDelete($category, $user);
case self::BULK_DELETE_DOCUMENTS_POST:
return $this->canBulkDeleteFromRequest($user);
}
throw new \LogicException('Unhandled attribute. Please check supports() method.');
}
private function canView($object, User $user)
{
if($object instanceof Document) {
$category = $object->getCategory();
} else {
$category = $object;
}
// Est-ce que j'ai l'ACL 'éditer les documents' ?
// Récupération de l'ID du groupe ED
/** @var ContactsRepository $contactsRepository */
$contactsRepository = $this->entityManager->getRepository(Contacts::class);
$contact = $contactsRepository->findOneBy(['xutilisateur' => $user->getId()]);
if(!$contact) {
return false;
}
$groupId = $contact->getGroup();
// Si je suis dans un groupe ED
if($groupId) {
// Récupération du groupe ED
/** @var UserGroupRepository $userGroupsRepository */
$userGroupsRepository = $this->edEntityManager->getRepository(UserGroup::class);
$userGroup = $userGroupsRepository->find($groupId);
// Si je suis dans le groupe 'admin', dans tous les cas, j'ai le droit d'éditer
if('admins' === $userGroup->getSlug()) {
return true;
}
/** @var AclRepository $aclsRepository */
$aclsRepository = $this->edEntityManager->getRepository(Acl::class);
return (
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::EDIT_CATEGORY) || // Si j'ai le droit d'éditer la catégorie, j'ai aussi le droit d'éditer les documents
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::EDIT_DOCUMENTS) ||
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::VIEW)
);
}
return false;
}
/**
* @param Category $category
* @param User $user
* @return bool
* @throws \Doctrine\ORM\NonUniqueResultException
*/
private function canEdit(Category $category, User $user)
{
// Est-ce que j'ai l'ACL 'éditer' ?
// Récupération de l'ID du groupe ED
/** @var ContactsRepository $contactsRepository */
$contactsRepository = $this->entityManager->getRepository(Contacts::class);
$contact = $contactsRepository->findOneBy(['xutilisateur' => $user->getId()]);
$groupId = $contact->getGroup();
// Si je suis dans un groupe ED
if($groupId) {
// Récupération du groupe ED
/** @var UserGroupRepository $userGroupsRepository */
$userGroupsRepository = $this->edEntityManager->getRepository(UserGroup::class);
$userGroup = $userGroupsRepository->find($groupId);
// Si je suis dans le groupe 'admin', dans tous les cas, j'ai le droit d'éditer
if('admins' === $userGroup->getSlug()) {
return true;
}
/** @var AclRepository $aclsRepository */
$aclsRepository = $this->edEntityManager->getRepository(Acl::class);
return $aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::EDIT_CATEGORY);
}
return false;
}
/**
* @param Category $category
* @param User $user
* @return bool
* @throws \Doctrine\ORM\NonUniqueResultException
*/
private function canEditDocuments(Category $category, User $user)
{
// Est-ce que j'ai l'ACL 'éditer les documents' ?
// Récupération de l'ID du groupe ED
/** @var ContactsRepository $contactsRepository */
$contactsRepository = $this->entityManager->getRepository(Contacts::class);
$contact = $contactsRepository->findOneBy(['xutilisateur' => $user->getId()]);
if(!$contact) {
return false;
}
$groupId = $contact->getGroup();
// Si je suis dans un groupe ED
if($groupId) {
// Récupération du groupe ED
/** @var UserGroupRepository $userGroupsRepository */
$userGroupsRepository = $this->edEntityManager->getRepository(UserGroup::class);
$userGroup = $userGroupsRepository->find($groupId);
// Si je suis dans le groupe 'admin', dans tous les cas, j'ai le droit d'éditer
if('admins' === $userGroup->getSlug()) {
return true;
}
/** @var AclRepository $aclsRepository */
$aclsRepository = $this->edEntityManager->getRepository(Acl::class);
return (
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::EDIT_CATEGORY) || // Si j'ai le droit d'éditer la catégorie, j'ai aussi le droit d'éditer les documents
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::EDIT_DOCUMENTS)
);
}
return false;
}
/**
* @param Category $category
* @param User $user
* @return bool
* @throws \Doctrine\ORM\NonUniqueResultException
*/
private function canViewDocuments(Category $category, User $user)
{
// Est-ce que j'ai l'ACL 'Voir les documents' ?
// Récupération de l'ID du groupe ED
/** @var ContactsRepository $contactsRepository */
$contactsRepository = $this->entityManager->getRepository(Contacts::class);
$contact = $contactsRepository->findOneBy(['xutilisateur' => $user->getId()]);
$groupId = $contact->getGroup();
// Si je suis dans un groupe ED
if($groupId) {
// Récupération du groupe ED
/** @var UserGroupRepository $userGroupsRepository */
$userGroupsRepository = $this->edEntityManager->getRepository(UserGroup::class);
$userGroup = $userGroupsRepository->find($groupId);
// Si je suis dans le groupe 'admin', dans tous les cas, j'ai le droit d'éditer
if('admins' === $userGroup->getSlug()) {
return true;
}
/** @var AclRepository $aclsRepository */
$aclsRepository = $this->edEntityManager->getRepository(Acl::class);
return (
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::EDIT_CATEGORY) || // Si j'ai le droit d'éditer la catégorie, j'ai aussi le droit d'éditer les documents
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::EDIT_DOCUMENTS) ||
$aclsRepository->groupHasAclForCategory($userGroup, $category, Acl::VIEW)
);
}
return false;
}
/**
* @param Category $category
* @param User $user
* @return bool
* @throws \Doctrine\ORM\NonUniqueResultException
*/
private function canDelete(Category $category, User $user)
{
return $this->canEdit($category, $user);
}
/**
* Vérifier si j'ai le droit de supprimer les documents dont les ID sont passés en POST, dans `delete_documents`
*
* @param $user
* @return bool
*/
private function canBulkDeleteFromRequest($user)
{
try {
/** @var DocumentRepository $documentRepository */
$documentRepository = $this->entityManager->getRepository(Document::class);
$documentsToDelete = $this->requestStack->getMasterRequest()->get('delete_documents');
foreach ($documentsToDelete as $key => $documentId) {
$document = $documentRepository->find($documentId);
if(!$this->canEditDocuments($document->getCategory(), $user)) {
return false;
}
}
return true;
} catch (\Exception $exception) {
return false;
}
}
}