src/Security/DemandVoter.php line 21

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/DemandVoter.php
  4. //------------------------------------------------------------------------------
  5. namespace App\Security;
  6. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  7. use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
  8. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  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\Demand\Demand;
  15. use App\Entity\Security\Acl;
  16. use App\Entity\Security\AclPermission;
  17. use App\Services\Config\ModuleTools;
  18. class DemandVoter extends Voter
  19. {
  20.     //--------------------------------------------------------------------------------
  21.     // is_granted constants
  22.     const IS_ACTIVE "demand_is_active";
  23.     const ADD "add_demand";
  24.     const CONVERT_TO_MISSION "convert_demand_to_mission";
  25.     const LINK_TO_MISSION "link_demand_to_mission";
  26.     const LISTING "list_demands";
  27.     const LISTING_SOCIETY "list_demands_society";
  28.     const LISTING_ANY "list_demands_any";
  29.     const VIEW "view_demand";
  30.     const EDIT "edit_demand";
  31.     const EDIT_SOCIETY "edit_demand_society";
  32.     const IS_GRANTED_CONSTANTS = array(
  33.         self::IS_ACTIVE,
  34.         self::ADD,
  35.         self::CONVERT_TO_MISSION,
  36.         self::LINK_TO_MISSION,
  37.         self::LISTING,
  38.         self::LISTING_SOCIETY,
  39.         self::LISTING_ANY,
  40.         self::VIEW,
  41.         self::EDIT,
  42.         self::EDIT_SOCIETY,
  43.     );
  44.     //--------------------------------------------------------------------------------
  45.     // acl constants
  46.     const ACL_PERM_ADD 'demand_add';
  47.     const ACL_PERM_LIST 'demand_list';
  48.     const ACL_PERM_LIST_SOCIETY 'demand_list_society';
  49.     const ACL_PERM_VIEW 'demand_view';
  50.     const ACL_PERM_VIEW_SOCIETY 'demand_view_society';
  51.     const ACL_PERM_EDIT 'demand_edit';
  52.     const ACL_PERM_EDIT_SOCIETY 'demand_edit_society';
  53.     const ACL_PERM_SOCIETY_EDIT 'demand_society_edit';
  54.     const ACL_PERM_SOCIETY_EDIT_SOCIETY 'demand_society_edit_society';
  55.     //--------------------------------------------------------------------------------
  56.     public function __construct(AccessDecisionManagerInterface $accessDecisionManagerManagerRegistry $doctrineModuleTools $moduleTools)
  57.     {
  58.         $this->accessDecisionManager $accessDecisionManager;
  59.         $this->em $doctrine->getManager();
  60.         $this->moduleTools $moduleTools;
  61.         $this->aclRepository $this->em->getRepository(Acl::class);
  62.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  63.     }
  64.     // Plan.io Task #4453 [See AccessVoter for details]
  65.     public function supportsAttribute(string $attribute): bool
  66.     {
  67.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  68.     }
  69.     protected function supports(string $attribute$subject null): bool
  70.     {
  71.         // if the attribute isn't one we support, return false
  72.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  73.         {
  74.             return false;
  75.         }
  76.         // only vote on Demand objects inside this voter
  77.         if ($subject !== null && !$subject instanceof Demand)
  78.         {
  79.             return false;
  80.         }
  81.         return true;
  82.     }
  83.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  84.     {
  85.         $user $token->getUser();
  86.         if (!$user instanceof Access)
  87.         {
  88.             // the user must be logged in; if not, deny access
  89.             return false;
  90.         }
  91.         // The user must have a function; if not deny access
  92.         $function $user->getFunction();
  93.         if ($function === null)        return false;
  94.         // Plan.io Task #3710 : Get current group
  95.         $currentGroup $user->getSocietyGroup();
  96.         if ($currentGroup === null)
  97.             return false;
  98.         // Module activated ?
  99.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_DEMAND))
  100.         {
  101.             return false;
  102.         }
  103.         // you know $subject is a Demand object, thanks to supports
  104.         /** @var Demand $demand */
  105.         $demand $subject;
  106.         // Check current group affectation
  107.         if ($subject !== null)
  108.         {
  109.             $subjectSociety $subject->getSociety();
  110.             if ($subjectSociety === null)
  111.                 return false;
  112.             $subjectGroup $subjectSociety->getGroup();
  113.             if ($subjectGroup === null)
  114.                 return false;
  115.             if (!$currentGroup->equals($subjectGroup))
  116.                 return false;
  117.         }
  118.         switch ($attribute)
  119.         {
  120.             // Check is done before, in the voteOnAttribute
  121.             case self::IS_ACTIVE:
  122.                 return true;
  123.             case self::ADD:
  124.                 return $this->canAdd($demand$user$function);
  125.             case self::CONVERT_TO_MISSION:
  126.                 return $this->canConvertToMission($demand$user$function$token);
  127.             case self::LINK_TO_MISSION:
  128.                 return $this->canLinkToMission($demand$user$function$token);
  129.             case self::VIEW:
  130.                 return $this->canView($demand$user$function);
  131.             case self::EDIT:
  132.                 return $this->canEdit($demand$user$function);
  133.             case self::EDIT_SOCIETY:
  134.                 return $this->canEditSociety($demand$user$function);
  135.             case self::LISTING:
  136.                 return $this->canList($user$function);
  137.             case self::LISTING_SOCIETY:
  138.                 return $this->canListSociety($user$function);
  139.             case self::LISTING_ANY:
  140.                 return $this->canListAny($user$function);
  141.         }
  142.         throw new \LogicException('This code should not be reached!');
  143.     }
  144.     // $access is the user trying to load the resource
  145.     // $demand is the resource being loaded
  146.     // Check if the Author of the Demand is the Access
  147.     private function checkAuthor(Demand $demandAccess $access)
  148.     {
  149.         // Get the Society of the Demand
  150.         $demandAuthor $demand->getAuthor();
  151.         if ($demandAuthor === null)
  152.             return false;
  153.         if ($access->getId() == $demandAuthor->getId())
  154.             return true;
  155.         return false;
  156.     }
  157.     // Check if the Society of the Demand
  158.     // belongs to the societies of the $access
  159.     private function checkSociety(Demand $demandAccess $access)
  160.     {
  161.         // Get all the societies of the access
  162.         $societies $access->getSocieties();
  163.         // Get the Society of the Demand
  164.         $demandSociety $demand->getSociety();
  165.         if ($demandSociety === null)
  166.             return false;
  167.         $found false;
  168.         foreach ($societies as $society)
  169.         {
  170.             if ($society->getId() == $demandSociety->getId())
  171.             {
  172.                 $found true;
  173.                 break;
  174.             }
  175.         }
  176.         return $found;
  177.     }
  178.     private function canAdd(Demand $demand nullAccess $userAccessFunction $function)
  179.     {
  180.         // Get Acl_Perdemand
  181.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD);
  182.         if ($aclPerm === null)        return false;
  183.         // Get Acl
  184.         $acl $this->aclRepository->findOneBy(array(
  185.             'function'        =>    $function,
  186.             'permission'    =>    $aclPerm
  187.         ));
  188.         if ($acl === null)        return false;
  189.         // Since only one acl type can exist
  190.         // we can return the result of the acl_permission
  191.         return $acl->getValue();
  192.     }
  193.     private function canConvertToMission(Demand $demandAccess $userAccessFunction $function$token)
  194.     {
  195.         if ($demand->getClient() === null)
  196.         {
  197.             // This should not happen
  198.             return false;
  199.         }
  200.         if ($demand->getMission() !== null)
  201.         {
  202.             // Already attached to a mission
  203.             return false;
  204.         }
  205.         if ($demand->getResultingMission() !== null)
  206.         {
  207.             // Already converted to a mission
  208.             return false;
  209.         }
  210.         // Request permission to add missions
  211.         $canAddMissions $this->accessDecisionManager->decide($token, ['add_mission']);
  212.         // Request permission to edit this demand
  213.         $canEditDemand $this->canEdit($demand$user$function);
  214.         // 27/10/2022 : For the moment don't allow other demand than jcafLocal
  215.         $isJcafLocal false;
  216.         if ($demand->getType() !== null)
  217.         {
  218.             $isJcafLocal $demand->getType()->getJcafLocal();
  219.         }
  220.         if ($canAddMissions && $canEditDemand && $isJcafLocal)
  221.         {
  222.             return true;
  223.         }
  224.         return false;
  225.     }
  226.     private function canLinkToMission(Demand $demandAccess $userAccessFunction $function$token)
  227.     {
  228.         if ($demand->getClient() === null)
  229.         {
  230.             // This should not happen
  231.             return false;
  232.         }
  233.         if ($demand->getMission() !== null)
  234.         {
  235.             // Already attached to a mission
  236.             return false;
  237.         }
  238.         if ($demand->getResultingMission() !== null)
  239.         {
  240.             // Already converted to a mission
  241.             return false;
  242.         }
  243.         // Request permission to edit this demand
  244.         $canEditDemand $this->canEdit($demand$user$function);
  245.         if ($canEditDemand)
  246.         {
  247.             return true;
  248.         }
  249.         return false;
  250.     }
  251.     private function canView(Demand $demand nullAccess $userAccessFunction $function)
  252.     {
  253.         // Get Acl_Perdemands
  254.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW);
  255.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_SOCIETY);
  256.         // If all are null, exit
  257.         if ($aclPerm === null && $aclPermSociety === null)
  258.             return false;
  259.         // Get First one
  260.         if ($aclPerm !== null)
  261.         {
  262.             $acl $this->aclRepository->findOneBy(array(
  263.                 'function'        =>    $function,
  264.                 'permission'    =>    $aclPerm
  265.             ));
  266.             if ($acl !== null)
  267.             {
  268.                 if ($acl->getValue())
  269.                 {
  270.                     // A single positive answer is enough
  271.                     return true;
  272.                 }
  273.             }
  274.         }
  275.         // If we are here it means that nothing good has been found
  276.         // Load second permission
  277.         if ($aclPermSociety !== null)
  278.         {
  279.             $acl $this->aclRepository->findOneBy(array(
  280.                 'function'        =>    $function,
  281.                 'permission'    =>    $aclPermSociety
  282.             ));
  283.             if ($acl !== null)
  284.             {
  285.                 if ($acl->getValue())
  286.                 {
  287.                     // Check Society : also check author
  288.                     // Les demands appartenant à ses sociétés (et celles dont il est l'auteur)
  289.                     if ($this->checkSociety($demand$user))
  290.                     {
  291.                         return true;
  292.                     }
  293.                     else
  294.                     {
  295.                         return $this->checkAuthor($demand$user);
  296.                     }
  297.                 }
  298.             }
  299.         }
  300.         // If we are here, all hope is lost
  301.         return false;
  302.     }
  303.     private function canEdit(Demand $demand nullAccess $userAccessFunction $function)
  304.     {
  305.         // Get Acl_Perdemands
  306.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  307.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_SOCIETY);
  308.         // If all are null, exit
  309.         if ($aclPerm === null && $aclPermSociety === null)
  310.             return false;
  311.         // Get First one
  312.         if ($aclPerm !== null)
  313.         {
  314.             $acl $this->aclRepository->findOneBy(array(
  315.                 'function'        =>    $function,
  316.                 'permission'    =>    $aclPerm
  317.             ));
  318.             if ($acl !== null)
  319.             {
  320.                 if ($acl->getValue())
  321.                 {
  322.                     // A single positive answer is enough
  323.                     return true;
  324.                 }
  325.             }
  326.         }
  327.         // If we are here it means that nothing good has been found
  328.         // Load second permission
  329.         if ($aclPermSociety !== null)
  330.         {
  331.             $acl $this->aclRepository->findOneBy(array(
  332.                 'function'        =>    $function,
  333.                 'permission'    =>    $aclPermSociety
  334.             ));
  335.             if ($acl !== null)
  336.             {
  337.                 if ($acl->getValue())
  338.                 {
  339.                     // Check Society : also check author
  340.                     // Les demands appartenant à ses sociétés (et celles dont il est l'auteur)
  341.                     if ($this->checkSociety($demand$user))
  342.                     {
  343.                         return true;
  344.                     }
  345.                     else
  346.                     {
  347.                         return $this->checkAuthor($demand$user);
  348.                     }
  349.                 }
  350.             }
  351.         }
  352.         // If we are here, all hope is lost
  353.         return false;
  354.     }
  355.     private function canEditSociety(Demand $demand nullAccess $userAccessFunction $function)
  356.     {
  357.         // Get Acl_Perdemands
  358.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_SOCIETY_EDIT);
  359.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_SOCIETY_EDIT_SOCIETY);
  360.         // If all are null, exit
  361.         if ($aclPerm === null && $aclPermSociety === null)
  362.             return false;
  363.         // Get First one
  364.         if ($aclPerm !== null)
  365.         {
  366.             $acl $this->aclRepository->findOneBy(array(
  367.                 'function'        =>    $function,
  368.                 'permission'    =>    $aclPerm
  369.             ));
  370.             if ($acl !== null)
  371.             {
  372.                 if ($acl->getValue())
  373.                 {
  374.                     // A single positive answer is enough
  375.                     return true;
  376.                 }
  377.             }
  378.         }
  379.         // If we are here it means that nothing good has been found
  380.         // Load second permission
  381.         if ($aclPermSociety !== null)
  382.         {
  383.             $acl $this->aclRepository->findOneBy(array(
  384.                 'function'        =>    $function,
  385.                 'permission'    =>    $aclPermSociety
  386.             ));
  387.             if ($acl !== null)
  388.             {
  389.                 if ($acl->getValue())
  390.                 {
  391.                     // Check Society : also check author
  392.                     // Les demands appartenant à ses sociétés (et celles dont il est l'auteur)
  393.                     if ($this->checkSociety($demand$user))
  394.                     {
  395.                         return true;
  396.                     }
  397.                     else
  398.                     {
  399.                         return $this->checkAuthor($demand$user);
  400.                     }
  401.                 }
  402.             }
  403.         }
  404.         // If we are here, all hope is lost
  405.         return false;
  406.     }
  407.     private function canList(Access $userAccessFunction $function)
  408.     {
  409.         // If canView, then canList ;)
  410.         // Get Acl_Perdemand
  411.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LIST);
  412.         if ($aclPerm === null)        return false;
  413.         // Get Acl
  414.         $acl $this->aclRepository->findOneBy(array(
  415.             'function'        =>    $function,
  416.             'permission'    =>    $aclPerm
  417.         ));
  418.         if ($acl === null)        return false;
  419.         // Since only one acl type can exist
  420.         // we can return the result of the acl_permission
  421.         return $acl->getValue();
  422.     }
  423.     private function canListSociety(Access $userAccessFunction $function)
  424.     {
  425.         // If canView, then canList ;)
  426.         // Get Acl_Perdemand
  427.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LIST_SOCIETY);
  428.         if ($aclPerm === null)        return false;
  429.         // Get Acl
  430.         $acl $this->aclRepository->findOneBy(array(
  431.             'function'        =>    $function,
  432.             'permission'    =>    $aclPerm
  433.         ));
  434.         if ($acl === null)        return false;
  435.         // Since only one acl type can exist
  436.         // we can return the result of the acl_permission
  437.         return $acl->getValue();
  438.     }
  439.     private function canListAny(Access $userAccessFunction $function)
  440.     {
  441.         // Three Acl_Perdemand may exist
  442.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LIST);
  443.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LIST_SOCIETY);
  444.         // If all are null, exit
  445.         if ($aclPerm === null && $aclPermSociety === null)
  446.             return false;
  447.         // Get First one
  448.         if ($aclPerm !== null)
  449.         {
  450.             $acl $this->aclRepository->findOneBy(array(
  451.                 'function'        =>    $function,
  452.                 'permission'    =>    $aclPerm
  453.             ));
  454.             if ($acl !== null)
  455.             {
  456.                 if ($acl->getValue())
  457.                 {
  458.                     // A single positive answer is enough
  459.                     return true;
  460.                 }
  461.             }
  462.         }
  463.         // If we are here it means that nothing good has been found
  464.         // Load second permission
  465.         if ($aclPermSociety !== null)
  466.         {
  467.             $acl $this->aclRepository->findOneBy(array(
  468.                 'function'        =>    $function,
  469.                 'permission'    =>    $aclPermSociety
  470.             ));
  471.             if ($acl !== null)
  472.             {
  473.                 if ($acl->getValue())
  474.                 {
  475.                     // A single positive answer is enough
  476.                     return true;
  477.                 }
  478.             }
  479.         }
  480.         // If we are here, all hope is lost
  481.         return false;
  482.     }
  483. }