src/Security/SocietyVoter.php line 74

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/SocietyVoter.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\Common\Collections\ArrayCollection;
  9. use Doctrine\Persistence\ManagerRegistry;
  10. use App\Entity\Access;
  11. use App\Entity\Config\Config;
  12. use App\Entity\Config\Module;
  13. use App\Entity\HR\AccessFunction;
  14. use App\Entity\Platform\Society;
  15. use App\Entity\Security\Acl;
  16. use App\Entity\Security\AclPermission;
  17. use App\Services\Config\ModuleTools;
  18. class SocietyVoter extends Voter
  19. {
  20.     //--------------------------------------------------------------------------
  21.     // Plan.io Task #3634
  22.     const IS_ACTIVE "society_is_active";
  23.     const DISPLAY_SINGLE_SOCIETY "display_single_society";
  24.     const DISPLAY_MULTIPLE_SOCIETY "display_multiple_societies";
  25.     //--------------------------------------------------------------------------
  26.     const ADD "add_society";
  27.     const LISTING "list_societies";
  28.     const LISTING_SOCIETY "list_societies_society";
  29.     const LISTING_ANY "list_societies_any";
  30.     const VIEW "view_society";
  31.     const EDIT "edit_society";
  32.     const DELETE "delete_society";
  33.     const IS_GRANTED_CONSTANTS = array(
  34.         self::ADD,
  35.         self::LISTING,
  36.         self::LISTING_SOCIETY,
  37.         self::LISTING_ANY,
  38.         self::VIEW,
  39.         self::EDIT,
  40.         self::DELETE,
  41.         // Plan.io Task #3634
  42.         self::IS_ACTIVE,
  43.         self::DISPLAY_SINGLE_SOCIETY,
  44.         self::DISPLAY_MULTIPLE_SOCIETY,
  45.     );
  46.     //--------------------------------------------------------------------------------
  47.     // acl constants
  48.     const ACL_PERM_ADD "society_add";
  49.     const ACL_PERM_LISTING "society_list";
  50.     const ACL_PERM_LISTING_SOCIETY "society_list_society";
  51.     const ACL_PERM_VIEW "society_view";
  52.     const ACL_PERM_VIEW_SOCIETY "society_view_society";
  53.     const ACL_PERM_EDIT "society_edit";
  54.     const ACL_PERM_EDIT_SOCIETY "society_edit_society";
  55.     public function __construct(ManagerRegistry $doctrineModuleTools $moduleTools)
  56.     {
  57.         $this->em $doctrine->getManager();
  58.         $this->moduleTools $moduleTools;
  59.         $this->aclRepository $this->em->getRepository(Acl::class);
  60.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  61.     }
  62.     // Plan.io Task #4453 [See AccessVoter for details]
  63.     public function supportsAttribute(string $attribute): bool
  64.     {
  65.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  66.     }
  67.     
  68.     protected function supports(string $attribute$subject): bool
  69.     {
  70.         // if the attribute isn't one we support, return false
  71.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  72.         {
  73.             return false;
  74.         }
  75.         // only vote on Society objects inside this voter
  76.         if ($subject !== null && !$subject instanceof Society)
  77.         {
  78.             return false;
  79.         }
  80.         return true;
  81.     }
  82.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  83.     {
  84.         $user $token->getUser();
  85.         if (!$user instanceof Access)
  86.         {
  87.             // the user must be logged in; if not, deny access
  88.             return false;
  89.         }
  90.         // The user must have a function; if not deny access
  91.         $function $user->getFunction();
  92.         if ($function === null)        return false;
  93.         // Plan.io Task #3710 : Get current group
  94.         $currentGroup $user->getSocietyGroup();
  95.         if ($currentGroup === null)
  96.             return false;
  97.         // you know $subject is a Society object, thanks to supports
  98.         /** @var Society $society */
  99.         $society $subject;
  100.         // Check current group affectation
  101.         if ($subject !== null)
  102.         {
  103.             $subjectGroup $subject->getGroup();
  104.             if ($subjectGroup === null)
  105.                 return false;
  106.             if (!$currentGroup->equals($subjectGroup))
  107.                 return false;
  108.         }
  109.         switch ($attribute)
  110.         {
  111.             //------------------------------------------------------------------
  112.             // Plan.io Task #3634
  113.             case self::IS_ACTIVE:
  114.             {
  115.                 return $this->moduleTools->isActiveMultipleSocieties($currentGroup);
  116.             }
  117.             case self::DISPLAY_SINGLE_SOCIETY:
  118.             {
  119.                 return $this->moduleTools->isActiveSingleSociety($currentGroup);
  120.             }
  121.             case self::DISPLAY_MULTIPLE_SOCIETY:
  122.             {
  123.                 return $this->moduleTools->isActiveMultipleSocieties($currentGroup);
  124.             }
  125.             //------------------------------------------------------------------
  126.             case self::ADD:
  127.                 return $this->canAdd($society$user$function);
  128.             case self::LISTING:
  129.                 return $this->canList($society$user$function);
  130.             case self::LISTING_SOCIETY:
  131.                 return $this->canListSociety($society$user$function);
  132.             case self::LISTING_ANY:
  133.                 return $this->canListAny($society$user$function);
  134.             case self::VIEW:
  135.                 return $this->canView($society$user$function);
  136.             case self::EDIT:
  137.                 return $this->canEdit($society$user$function);
  138.             case self::DELETE:
  139.                 return $this->canDelete($society$user$function);
  140.         }
  141.         throw new \LogicException('This code should not be reached!');
  142.     }
  143.     // The access has a list of societies
  144.     // Thus, the access has one or more society groups (ASGS)
  145.     // The given society has a group SG
  146.     // We need to knoe if the group SG is one of ASGS
  147.     private function checkSociety(Society $societyAccess $access)
  148.     {
  149.         // Get all the societies of the access
  150.         $accessSocieties $access->getSocieties();
  151.         // Get all the groups of the access
  152.         $accessGroups = new \Doctrine\Common\Collections\ArrayCollection();
  153.         foreach ($accessSocieties as $as)
  154.         {
  155.             if ($accessGroups->contains($as->getGroup()) == false)
  156.             {
  157.                 $accessGroups[] = $as->getGroup();
  158.             }
  159.         }
  160.         // Get the society group of the Society
  161.         $societyGroup $society->getGroup();
  162.         if ($societyGroup === null)
  163.             return false;
  164.         foreach ($accessGroups as $ag)
  165.         {
  166.             if ($ag->getId() == $societyGroup->getId())
  167.             {
  168.                 return true;
  169.             }
  170.         }
  171.         return false;
  172.     }
  173.     private function canAdd(Society $society nullAccess $accessAccessFunction $function)
  174.     {
  175.         // Get Acl_Permission
  176.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD);
  177.         if ($aclPerm === null)        return false;
  178.         // Get Acl
  179.         $acl $this->aclRepository->findOneBy(array(
  180.             'function'        =>    $function,
  181.             'permission'    =>    $aclPerm
  182.         ));
  183.         if ($acl === null)        return false;
  184.         return $acl->getValue();
  185.     }
  186.     private function canList(Society $society nullAccess $accessAccessFunction $function)
  187.     {
  188.         // Restrictions are also applied in the Controller
  189.         // But this helps speeding page loading if the access is not even allowed to load the page
  190.         // (ie. if it has no list privileges whatsoever)
  191.         // Get Acl_Permission
  192.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  193.         if ($aclPerm === null)        return false;
  194.         // Get Acl
  195.         $acl $this->aclRepository->findOneBy(array(
  196.             'function'        =>    $function,
  197.             'permission'    =>    $aclPerm
  198.         ));
  199.         if ($acl === null)        return false;
  200.         // Since only one list type can exist for the Societys,
  201.         // we can return the result of the acl_permission
  202.         return $acl->getValue();
  203.     }
  204.     private function canListSociety(Society $society nullAccess $accessAccessFunction $function)
  205.     {
  206.         // Get Acl_Permission
  207.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  208.         if ($aclPerm === null)        return false;
  209.         // Get Acl
  210.         $acl $this->aclRepository->findOneBy(array(
  211.             'function'        =>    $function,
  212.             'permission'    =>    $aclPerm
  213.         ));
  214.         if ($acl === null)        return false;
  215.         // Since only one acl type can exist
  216.         // we can return the result of the acl_permission
  217.         // Further filtering is done in the Controller
  218.         return $acl->getValue();
  219.     }
  220.     private function canListAny(Society $society nullAccess $accessAccessFunction $function)
  221.     {
  222.         // Several Acl_Permission may exist
  223.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  224.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  225.         // If all are null, exit
  226.         if ($aclPerm === null && $aclPermSociety === null)
  227.             return false;
  228.         // Get First one
  229.         if ($aclPerm !== null)
  230.         {
  231.             $acl $this->aclRepository->findOneBy(array(
  232.                 'function'        =>    $function,
  233.                 'permission'    =>    $aclPerm
  234.             ));
  235.             if ($acl !== null)
  236.             {
  237.                 if ($acl->getValue())
  238.                 {
  239.                     // A single positive answer is enough
  240.                     return true;
  241.                 }
  242.             }
  243.         }
  244.         // If we are here it means that nothing good has been found
  245.         // Load second permission
  246.         if ($aclPermSociety !== null)
  247.         {
  248.             $acl $this->aclRepository->findOneBy(array(
  249.                 'function'        =>    $function,
  250.                 'permission'    =>    $aclPermSociety
  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, all hope is lost
  262.         return false;
  263.     }
  264.     private function canView(Society $societyAccess $accessAccessFunction $function)
  265.     {
  266.         // Several Acl_Permission exist
  267.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW);
  268.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_SOCIETY);
  269.         // If all are null, exit
  270.         if ($aclPerm === null || $aclPermSociety === null)
  271.             return false;
  272.         // Get First one (view all)
  273.         if ($aclPerm !== null)
  274.         {
  275.             $acl $this->aclRepository->findOneBy(array(
  276.                 'function'        =>    $function,
  277.                 'permission'    =>    $aclPerm
  278.             ));
  279.             if ($acl !== null)
  280.             {
  281.                 if ($acl->getValue())
  282.                 {
  283.                     // A single positive answer is enough
  284.                     return true;
  285.                 }
  286.             }
  287.         }
  288.         // If we are here it means that nothing good has been found
  289.         // Load second permission (restricred view)
  290.         if ($aclPermSociety !== null)
  291.         {
  292.             $acl $this->aclRepository->findOneBy(array(
  293.                 'function'        =>    $function,
  294.                 'permission'    =>    $aclPermSociety
  295.             ));
  296.             if ($acl !== null)
  297.             {
  298.                 if ($acl->getValue())
  299.                 {
  300.                     // A single positive answer is enough
  301.                     // In this case the good answer will be provided by the checkSociety
  302.                     return $this->checkSociety($society$access);
  303.                 }
  304.             }
  305.         }
  306.         // If we are here, all hope is lost
  307.         return false;
  308.     }
  309.     private function canEdit(Society $societyAccess $accessAccessFunction $function)
  310.     {
  311.         // Several Acl_Permission exist
  312.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  313.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_SOCIETY);
  314.         // If all are null, exit
  315.         if ($aclPerm === null || $aclPermSociety === null)
  316.             return false;
  317.         // Get First one (view all)
  318.         if ($aclPerm !== null)
  319.         {
  320.             $acl $this->aclRepository->findOneBy(array(
  321.                 'function'        =>    $function,
  322.                 'permission'    =>    $aclPerm
  323.             ));
  324.             if ($acl !== null)
  325.             {
  326.                 if ($acl->getValue())
  327.                 {
  328.                     // A single positive answer is enough
  329.                     return true;
  330.                 }
  331.             }
  332.         }
  333.         // If we are here it means that nothing good has been found
  334.         // Load second permission (restricred view)
  335.         if ($aclPermSociety !== null)
  336.         {
  337.             $acl $this->aclRepository->findOneBy(array(
  338.                 'function'        =>    $function,
  339.                 'permission'    =>    $aclPermSociety
  340.             ));
  341.             if ($acl !== null)
  342.             {
  343.                 if ($acl->getValue())
  344.                 {
  345.                     // A single positive answer is enough
  346.                     // In this case the good answer will be provided by the checkSociety
  347.                     return $this->checkSociety($society$access);
  348.                 }
  349.             }
  350.         }
  351.         // If we are here, all hope is lost
  352.         return false;
  353.     }
  354.     private function canDelete(Society $societyAccess $accessAccessFunction $function)
  355.     {
  356.         // Deny for all (admin is accepted in the calling function)
  357.         return false;
  358.     }
  359. }