src/Security/ArticleVoter.php line 72

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/ArticleVoter.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\Article;
  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 ArticleVoter extends Voter
  20. {
  21.     //--------------------------------------------------------------------------------
  22.     // is_granted constants
  23.     const IS_ACTIVE "article_is_active";
  24.     const ADD "add_article";
  25.     const VIEW "view_article";
  26.     const EDIT "edit_article";
  27.     const APPROVE "approve_article";
  28.     const DELETE "delete_article";
  29.     const ADD_COMMENT "add_comment";
  30.     const MODERATION "article_moderation";
  31.     const LIST_ANY "list_article_any";
  32.     const IS_GRANTED_CONSTANTS = array(
  33.         self::IS_ACTIVE,
  34.         self::ADD,
  35.         self::VIEW,
  36.         self::EDIT,
  37.         self::APPROVE,
  38.         self::DELETE,
  39.         self::ADD_COMMENT,
  40.         self::MODERATION,
  41.         self::LIST_ANY,
  42.     );
  43.     //--------------------------------------------------------------------------------
  44.     // acl constants
  45.     const ACL_PERM_ADD "article_add";
  46.     const ACL_PERM_EDIT "article_edit";
  47.     //const ACL_PERM_EDIT_OWN = "article_edit_own";
  48.     const ACL_PERM_APPROVE "article_approve";
  49.     //const ACL_PERM_APPROVE_OWN = "article_approve_own";
  50.     const ACL_PERM_DELETE "article_delete";
  51.     //const ACL_PERM_DELETE_OWN = "article_delete_own";
  52.     const ACL_PERM_ADD_COMMENT "article_comment_add";
  53.     //--------------------------------------------------------------------------------
  54.     public function __construct(ManagerRegistry $doctrineModuleTools $moduleTools)
  55.     {
  56.         $this->em $doctrine->getManager();
  57.         $this->moduleTools $moduleTools;
  58.         $this->aclRepository $this->em->getRepository(Acl::class);
  59.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  60.     }
  61.     // Plan.io Task #4453 [See AccessVoter for details]
  62.     public function supportsAttribute(string $attribute): bool
  63.     {
  64.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  65.     }
  66.     protected function supports(string $attribute$subject): bool
  67.     {
  68.         // if the attribute isn't one we support, return false
  69.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  70.         {
  71.             return false;
  72.         }
  73.         // only vote on Article objects inside this voter
  74.         if ($subject !== null && !$subject instanceof Article)
  75.         {
  76.             return false;
  77.         }
  78.         return true;
  79.     }
  80.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  81.     {
  82.         $user $token->getUser();
  83.         // Plan.io Task #3707
  84.         if ($user instanceof AccessAPI)
  85.         {
  86.             if ($user->getAccess() === null)
  87.             {
  88.                 return false;
  89.             }
  90.             $user $user->getAccess();
  91.         }
  92.         // Plan.io Task #3707
  93.         // At this point $user is an object of Access type
  94.         // even if the $token->getUser() is AccessAPI
  95.         if (!$user instanceof Access)
  96.         {
  97.             // the user must be logged in; if not, deny access
  98.             return false;
  99.         }
  100.         // The user must have a function; if not deny access
  101.         $function $user->getFunction();
  102.         if ($function === null)        return false;
  103.         // Plan.io Task #3710 : Get current group
  104.         $currentGroup $user->getSocietyGroup();
  105.         if ($currentGroup === null)
  106.             return false;
  107.         // Module activated ?
  108.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_ARTICLE))
  109.         {
  110.             return false;
  111.         }
  112.         // you know $subject is a Article object, thanks to supports
  113.         /** @var Article $article */
  114.         $article $subject;
  115.         // Check current group affectation
  116.         if ($subject !== null)
  117.         {
  118.             $subjectGroup $subject->getSocietyGroup();
  119.             if ($subjectGroup === null)
  120.                 return false;
  121.             if (!$currentGroup->equals($subjectGroup))
  122.                 return false;
  123.         }
  124.         switch ($attribute)
  125.         {
  126.             case self::IS_ACTIVE:
  127.                 return true;
  128.             case self::ADD:
  129.                 return $this->canAdd($user$function);
  130.             case self::VIEW:
  131.                 return $this->canView($article$user$function);
  132.             case self::EDIT:
  133.                 return $this->canEdit($article$user$function);
  134.             case self::DELETE:
  135.                 return $this->canDelete($article$user$function);
  136.             case self::APPROVE:
  137.                 return $this->canApprove($article$user$function);
  138.             case self::ADD_COMMENT:
  139.                 return $this->canAddComment($article$user$function);
  140.             case self::MODERATION:
  141.                 return $this->canModerate($user$function);
  142.             case self::LIST_ANY:
  143.                 return $this->canListAny($user$function);
  144.         }
  145.         throw new \LogicException('This code should not be reached!');
  146.     }
  147.     // $access is the user trying to load the resource
  148.     // $article is the resource being loaded
  149.     private function checkAuthor(Article $articleAccess $access)
  150.     {
  151.         $author $article->getAuthor();
  152.         if ($author === null)
  153.             return false;
  154.         if ($author->getId() == $access->getId())
  155.             return true;
  156.         return false;
  157.     }
  158.     private function canAdd(Access $userAccessFunction $function)
  159.     {
  160.         // Get AclPermission
  161.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD);
  162.         if ($aclPerm === null)        return false;
  163.         // Get Acl
  164.         $acl $this->aclRepository->findOneBy(array(
  165.             'function'        =>    $function,
  166.             'permission'    =>    $aclPerm
  167.         ));
  168.         if ($acl === null)        return false;
  169.         // Since only one acl type can exist
  170.         // we can return the result of the acl_permission
  171.         return $acl->getValue();
  172.     }
  173.     private function canView(Article $articleAccess $userAccessFunction $function)
  174.     {
  175.         if ($this->checkAuthor($article$user))
  176.             return true;
  177.         $acl $this->em->getRepository(AclArticle::class)
  178.             ->findOneBy(array(
  179.                 'article'                =>    $article,
  180.                 'accessFunction'        =>    $function,
  181.             ));
  182.         if ($acl === null)
  183.             return false;
  184.         return $acl->canView();
  185.     }
  186.     private function canEdit(Article $articleAccess $userAccessFunction $function)
  187.     {
  188.         // Always allow editing own's articles
  189.         if ($this->checkAuthor($article$user))
  190.             return true;
  191.         // Get AclPermissions
  192.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  193.         // If all are null, exit
  194.         if ($aclPerm === null)
  195.             return false;
  196.         // Get First one
  197.         if ($aclPerm !== null)
  198.         {
  199.             $acl $this->aclRepository->findOneBy(array(
  200.                 'function'        =>    $function,
  201.                 'permission'    =>    $aclPerm
  202.             ));
  203.             if ($acl !== null)
  204.             {
  205.                 if ($acl->getValue())
  206.                 {
  207.                     // A single positive answer is enough
  208.                     return true;
  209.                 }
  210.             }
  211.         }
  212.         // If we are here, all hope is lost
  213.         return false;
  214.     }
  215.     private function canApprove(Article $articleAccess $userAccessFunction $function)
  216.     {
  217.         // Get AclPermissions
  218.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_APPROVE);
  219.         // If all are null, exit
  220.         if ($aclPerm === null && $aclPermOwn === null)
  221.             return false;
  222.         // Get First one
  223.         if ($aclPerm !== null)
  224.         {
  225.             $acl $this->aclRepository->findOneBy(array(
  226.                 'function'        =>    $function,
  227.                 'permission'    =>    $aclPerm
  228.             ));
  229.             if ($acl !== null)
  230.             {
  231.                 if ($acl->getValue())
  232.                 {
  233.                     // A single positive answer is enough
  234.                     return true;
  235.                 }
  236.             }
  237.         }
  238.         // If we are here, all hope is lost
  239.         return false;
  240.     }
  241.     private function canDelete(Article $articleAccess $userAccessFunction $function)
  242.     {
  243.         // Always allow deleting own's articles
  244.         if ($this->checkAuthor($article$user))
  245.             return true;
  246.         // Get AclPermissions
  247.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE);
  248.         // If all are null, exit
  249.         if ($aclPerm === null)
  250.             return false;
  251.         // Get First one
  252.         if ($aclPerm !== null)
  253.         {
  254.             $acl $this->aclRepository->findOneBy(array(
  255.                 'function'        =>    $function,
  256.                 'permission'    =>    $aclPerm
  257.             ));
  258.             if ($acl !== null)
  259.             {
  260.                 if ($acl->getValue())
  261.                 {
  262.                     // A single positive answer is enough
  263.                     return true;
  264.                 }
  265.             }
  266.         }
  267.         // If we are here, all hope is lost
  268.         return false;
  269.     }
  270.     private function canAddComment(Article $articleAccess $userAccessFunction $function)
  271.     {
  272.         // Get AclPermissions
  273.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD_COMMENT);
  274.         // If all are null, exit
  275.         if ($aclPerm === null)
  276.             return false;
  277.         // Get First one
  278.         if ($aclPerm !== null)
  279.         {
  280.             $acl $this->aclRepository->findOneBy(array(
  281.                 'function'        =>    $function,
  282.                 'permission'    =>    $aclPerm
  283.             ));
  284.             if ($acl !== null)
  285.             {
  286.                 if ($acl->getValue())
  287.                 {
  288.                     // A single positive answer is enough
  289.                     return true;
  290.                 }
  291.             }
  292.         }
  293.         // If we are here, all hope is lost
  294.         return false;
  295.     }
  296.     private function canModerate(Access $userAccessFunction $function)
  297.     {
  298.         // Get AclPermissions
  299.         $acls = array();
  300.         $acls[] = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_APPROVE);
  301.         //$acls[] = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_APPROVE_OWN);
  302.         $acls[] = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  303.         //$acls[] = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_OWN);
  304.         $acls[] = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE);
  305.         //$acls[] = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE_OWN);
  306.         // If all are null, exit
  307.         $allNull true;
  308.         foreach ($acls as $acl)
  309.         {
  310.             if ($acl !== null)
  311.             {
  312.                 $allNull false;
  313.                 break;
  314.             }
  315.         }
  316.         if ($allNull)
  317.             return false;
  318.         // Test
  319.         foreach ($acls as $aclPerm)
  320.         {
  321.             if ($aclPerm !== null)
  322.             {
  323.                 $acl $this->aclRepository->findOneBy(array(
  324.                     'function'        =>    $function,
  325.                     'permission'    =>    $aclPerm
  326.                 ));
  327.                 if ($acl !== null)
  328.                 {
  329.                     if ($acl->getValue())
  330.                     {
  331.                         // A single positive answer is enough
  332.                         return true;
  333.                     }
  334.                 }
  335.             }
  336.         }
  337.         // If we are here, all hope is lost
  338.         return false;
  339.     }
  340.     public function canListAny(Access $userAccessFunction $function)
  341.     {
  342.         return true;
  343.     }
  344. }