src/Security/ArticleCommentVoter.php line 22

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/ArticleCommentVoter.php
  4. //------------------------------------------------------------------------------
  5. namespace App\Security;
  6. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  7. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  8. use Doctrine\Persistence\ManagerRegistry;
  9. use App\Entity\Access;
  10. use App\Entity\APIRest\AccessAPI;
  11. use App\Entity\Config\Config;
  12. use App\Entity\Config\Module;
  13. use App\Entity\HR\AccessFunction;
  14. use App\Entity\Media\Comment;
  15. use App\Entity\Security\Acl;
  16. use App\Entity\Security\AclArticle;
  17. use App\Entity\Security\AclPermission;
  18. use App\Services\Config\ModuleTools;
  19. class ArticleCommentVoter extends Voter
  20. {
  21.     //--------------------------------------------------------------------------------
  22.     // is_granted constants
  23.     const APPROVE "approve_comment";
  24.     const DELETE "delete_comment";
  25.     const MODERATION "comment_moderation";
  26.     const IS_GRANTED_CONSTANTS = array(
  27.         self::APPROVE,
  28.         self::DELETE,
  29.         self::MODERATION,
  30.     );
  31.     //--------------------------------------------------------------------------------
  32.     // acl constants
  33.     const ACL_PERM_APPROVE "article_comment_approve";
  34.     const ACL_PERM_APPROVE_OWN_ARTICLE "article_comment_approve_own_article";
  35.     const ACL_PERM_DELETE "article_comment_delete";
  36.     const ACL_PERM_DELETE_OWN_ARTICLE "article_comment_delete_own_article";
  37.     const ACL_PERM_DELETE_OWN "article_comment_delete_own";
  38.     //--------------------------------------------------------------------------------
  39.     public function __construct(ManagerRegistry $doctrineModuleTools $moduleTools)
  40.     {
  41.         $this->em $doctrine->getManager();
  42.         $this->moduleTools $moduleTools;
  43.         $this->aclRepository $this->em->getRepository(Acl::class);
  44.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  45.     }
  46.     // Plan.io Task #4453 [See AccessVoter for details]
  47.     public function supportsAttribute(string $attribute): bool
  48.     {
  49.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  50.     }
  51.     protected function supports(string $attribute$subject): bool
  52.     {
  53.         // if the attribute isn't one we support, return false
  54.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  55.         {
  56.             return false;
  57.         }
  58.         // only vote on Comment objects inside this voter
  59.         if ($subject !== null && !$subject instanceof Comment)
  60.         {
  61.             return false;
  62.         }
  63.         return true;
  64.     }
  65.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  66.     {
  67.         $user $token->getUser();
  68.         // Plan.io Task #3707
  69.         if ($user instanceof AccessAPI)
  70.         {
  71.             if ($user->getAccess() === null)
  72.             {
  73.                 return false;
  74.             }
  75.             $user $user->getAccess();
  76.         }
  77.         // Plan.io Task #3707
  78.         // At this point $user is an object of Access type
  79.         // even if the $token->getUser() is AccessAPI
  80.         if (!$user instanceof Access)
  81.         {
  82.             // the user must be logged in; if not, deny access
  83.             return false;
  84.         }
  85.         // The user must have a function; if not deny access
  86.         $function $user->getFunction();
  87.         if ($function === null)        return false;
  88.         // Plan.io Task #3710 : Get current group
  89.         $currentGroup $user->getSocietyGroup();
  90.         if ($currentGroup === null)
  91.             return false;
  92.         // Module activated ?
  93.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_ARTICLE))
  94.         {
  95.             return false;
  96.         }
  97.         // you know $subject is a Comment object, thanks to supports
  98.         /** @var Comment $comment */
  99.         $comment $subject;
  100.         // Check current group affectation
  101.         if ($subject !== null && $subject->getArticle() !== null)
  102.         {
  103.             $subjectGroup $subject->getArticle()->getSocietyGroup();
  104.             if ($subjectGroup === null)
  105.                 return false;
  106.             if (!$currentGroup->equals($subjectGroup))
  107.                 return false;
  108.         }
  109.         switch ($attribute)
  110.         {
  111.             case self::DELETE:
  112.                 return $this->canDelete($comment$user$function);
  113.             case self::APPROVE:
  114.                 return $this->canApprove($comment$user$function);
  115.             case self::MODERATION:
  116.                 return $this->canModerate($user$function);
  117.         }
  118.         throw new \LogicException('This code should not be reached!');
  119.     }
  120.     // $access is the user trying to load the resource
  121.     // $comment is the resource being loaded
  122.     private function checkAuthor(Comment $commentAccess $access)
  123.     {
  124.         $author $comment->getAuthor();
  125.         if ($author === null)
  126.             return false;
  127.         if ($author->getId() == $access->getId())
  128.             return true;
  129.         return false;
  130.     }
  131.     // $access is the user trying to load the resource
  132.     // $comment is the resource being loaded
  133.     private function checkArticleAuthor(Comment $commentAccess $access)
  134.     {
  135.         $article $comment->getArticle();
  136.         if ($article === null)
  137.             return false;
  138.         $author $article->getAuthor();
  139.         if ($author === null)
  140.             return false;
  141.         if ($author->getId() == $access->getId())
  142.             return true;
  143.         return false;
  144.     }
  145.     private function canModerate(Access $userAccessFunction $function)
  146.     {
  147.         // Get AclPermissions
  148.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_APPROVE);
  149.         $aclPermOwnArticle $this->aclPermissionRepository->findOneByName(self::ACL_PERM_APPROVE_OWN_ARTICLE);
  150.         // If all are null, exit
  151.         if ($aclPerm === null && $aclPermOwnArticle)
  152.             return false;
  153.         // Get First one
  154.         if ($aclPerm !== null)
  155.         {
  156.             $acl $this->aclRepository->findOneBy(array(
  157.                 'function'        =>    $function,
  158.                 'permission'    =>    $aclPerm
  159.             ));
  160.             if ($acl !== null)
  161.             {
  162.                 if ($acl->getValue())
  163.                 {
  164.                     // A single positive answer is enough
  165.                     return true;
  166.                 }
  167.             }
  168.         }
  169.         // If we are here it means that nothing good has been found
  170.         // Load second permission
  171.         if ($aclPermOwnArticle !== null)
  172.         {
  173.             $acl $this->aclRepository->findOneBy(array(
  174.                 'function'        =>    $function,
  175.                 'permission'    =>    $aclPermOwnArticle
  176.             ));
  177.             if ($acl !== null)
  178.             {
  179.                 if ($acl->getValue())
  180.                 {
  181.                     /// A single positive answer is enough
  182.                     return true;
  183.                 }
  184.             }
  185.         }
  186.         // If we are here, all hope is lost
  187.         return false;
  188.     }
  189.     private function canApprove(Comment $commentAccess $userAccessFunction $function)
  190.     {
  191.         // Get AclPermissions
  192.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_APPROVE);
  193.         $aclPermOwnArticle $this->aclPermissionRepository->findOneByName(self::ACL_PERM_APPROVE_OWN_ARTICLE);
  194.         // If all are null, exit
  195.         if ($aclPerm === null && $aclPermOwnArticle)
  196.             return false;
  197.         // Get First one
  198.         if ($aclPerm !== null)
  199.         {
  200.             $acl $this->aclRepository->findOneBy(array(
  201.                 'function'        =>    $function,
  202.                 'permission'    =>    $aclPerm
  203.             ));
  204.             if ($acl !== null)
  205.             {
  206.                 if ($acl->getValue())
  207.                 {
  208.                     // A single positive answer is enough
  209.                     return true;
  210.                 }
  211.             }
  212.         }
  213.         // If we are here it means that nothing good has been found
  214.         // Load second permission
  215.         if ($aclPermOwnArticle !== null)
  216.         {
  217.             $acl $this->aclRepository->findOneBy(array(
  218.                 'function'        =>    $function,
  219.                 'permission'    =>    $aclPermOwnArticle
  220.             ));
  221.             if ($acl !== null)
  222.             {
  223.                 if ($acl->getValue())
  224.                 {
  225.                     // A single positive answer is enough
  226.                     // In this case the good answer will be provided by the checkSociety
  227.                     return $this->checkArticleAuthor($comment$user);
  228.                 }
  229.             }
  230.         }
  231.         // If we are here, all hope is lost
  232.         return false;
  233.     }
  234.     private function canDelete(Comment $commentAccess $userAccessFunction $function)
  235.     {
  236.         // Always allow deleting own's comments
  237.         if ($this->checkAuthor($comment$user))
  238.             return true;
  239.         // Get AclPermissions
  240.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE);
  241.         $aclPermOwnArticle $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE_OWN_ARTICLE);
  242.         // If all are null, exit
  243.         if ($aclPerm === null && $aclPermOwnArticle === null)
  244.             return false;
  245.         // Get First one
  246.         if ($aclPerm !== null)
  247.         {
  248.             $acl $this->aclRepository->findOneBy(array(
  249.                 'function'        =>    $function,
  250.                 'permission'    =>    $aclPerm
  251.             ));
  252.             if ($acl !== null)
  253.             {
  254.                 if ($acl->getValue())
  255.                 {
  256.                     // A single positive answer is enough
  257.                     return true;
  258.                 }
  259.             }
  260.         }
  261.         // If we are here it means that nothing good has been found
  262.         // Load second permission
  263.         if ($aclPermOwnArticle !== null)
  264.         {
  265.             $acl $this->aclRepository->findOneBy(array(
  266.                 'function'        =>    $function,
  267.                 'permission'    =>    $aclPermOwnArticle
  268.             ));
  269.             if ($acl !== null)
  270.             {
  271.                 if ($acl->getValue())
  272.                 {
  273.                     // A single positive answer is enough
  274.                     // In this case the good answer will be provided by the checkSociety
  275.                     return $this->checkArticleAuthor($comment$user);
  276.                 }
  277.             }
  278.         }
  279.         // If we are here, all hope is lost
  280.         return false;
  281.     }
  282. }