src/Security/ApplicationVoter.php line 100

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/ApplicationVoter.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\Config\Config;
  11. use App\Entity\Config\Module;
  12. use App\Entity\HR\AccessFunction;
  13. use App\Entity\HR\Application\Application;
  14. use App\Entity\HR\Note;
  15. use App\Entity\Security\Acl;
  16. use App\Entity\Security\AclPermission;
  17. use App\Services\Config\ModuleTools;
  18. class ApplicationVoter extends Voter
  19. {
  20.     //--------------------------------------------------------------------------------
  21.     // is_granted constants
  22.     const IS_ACTIVE "application_is_active";
  23.     // JCAF refalted
  24.     const ACCEPT "accept_application";
  25.     const REFUSE "reject_application";
  26.     // Normal ones
  27.     const ADD "add_application";
  28.     const LISTING "list_applications";
  29.     const LISTING_SOCIETY "list_applications_society";
  30.     const LISTING_ANY "list_applications_any";
  31.     const VIEW "view_application";
  32.     const EDIT "edit_application";
  33.     const DELETE "delete_application";
  34.     const CONVERT "convert_application";
  35.     const ADD_NOTE "add_application_note";
  36.     const EDIT_NOTE "edit_application_note";
  37.     const DELETE_NOTE "delete_application_note";
  38.     const IS_GRANTED_CONSTANTS = array(
  39.         self::IS_ACTIVE,
  40.         self::ACCEPT,
  41.         self::REFUSE,
  42.         self::ADD,
  43.         self::LISTING,
  44.         self::LISTING_SOCIETY,
  45.         self::LISTING_ANY,
  46.         self::VIEW,
  47.         self::EDIT,
  48.         self::DELETE,
  49.         self::CONVERT,
  50.         self::ADD_NOTE,
  51.         self::EDIT_NOTE,
  52.         self::DELETE_NOTE,
  53.     );
  54.     //--------------------------------------------------------------------------------
  55.     // acl constants
  56.     const ACL_PERM_ADD "application_add";
  57.     const ACL_PERM_LISTING "application_list";
  58.     const ACL_PERM_LISTING_SOCIETY "application_list_society";
  59.     const ACL_PERM_VIEW "application_view";
  60.     const ACL_PERM_VIEW_SOCIETY "application_view_society";
  61.     const ACL_PERM_EDIT "application_edit";
  62.     const ACL_PERM_EDIT_SOCIETY "application_edit_society";
  63.     const ACL_PERM_DELETE "application_delete";
  64.     const ACL_PERM_DELETE_SOCIETY "application_delete_society";
  65.     const ACL_PERM_CONVERT "application_convert";
  66.     const ACL_PERM_ADD_NOTE "application_add_note";
  67.     const ACL_PERM_ADD_NOTE_SOCIETY "application_add_note_society";
  68.     const ACL_PERM_EDIT_NOTE "application_edit_note";
  69.     const ACL_PERM_EDIT_NOTE_SOCIETY "application_edit_note_society";
  70.     const ACL_PERM_DELETE_NOTE "application_delete_note";
  71.     const ACL_PERM_DELETE_NOTE_SOCIETY "application_delete_note_society";
  72.     //--------------------------------------------------------------------------------
  73.     public function __construct(ManagerRegistry $doctrineModuleTools $moduleTools)
  74.     {
  75.         $this->em $doctrine->getManager();
  76.         $this->moduleTools $moduleTools;
  77.         $this->aclRepository $this->em->getRepository(Acl::class);
  78.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  79.     }
  80.     // Plan.io Task #4453 [See AccessVoter for details]
  81.     public function supportsAttribute(string $attribute): bool
  82.     {
  83.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  84.     }
  85.     
  86.     protected function supports(string $attribute$subject): bool
  87.     {
  88.         // if the attribute isn't one we support, return false
  89.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  90.         {
  91.             return false;
  92.         }
  93.         // only vote on Application objects inside this voter
  94.         if ($subject !== null && !$subject instanceof Application && !$subject instanceof Note)
  95.         {
  96.             return false;
  97.         }
  98.         return true;
  99.     }
  100.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  101.     {
  102.         $user $token->getUser();
  103.         if (!$user instanceof Access)
  104.         {
  105.             // the user must be logged in; if not, deny access
  106.             return false;
  107.         }
  108.         // The user must have a function; if not deny access
  109.         $function $user->getFunction();
  110.         if ($function === null)        return false;
  111.         // Plan.io Task #3710 : Get current group
  112.         $currentGroup $user->getSocietyGroup();
  113.         if ($currentGroup === null)
  114.             return false;
  115.         $this->currentGroup $currentGroup;
  116.         // Module activated ?
  117.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_APPLICATION))
  118.         {
  119.             return false;
  120.         }
  121.         // Check current group affectation
  122.         if ($subject !== null)
  123.         {
  124.             $subjectSociety $subject->getSociety();
  125.             if ($subjectSociety === null)
  126.                 return false;
  127.             $subjectGroup $subjectSociety->getGroup();
  128.             if ($subjectGroup === null)
  129.                 return false;
  130.             if (!$currentGroup->equals($subjectGroup))
  131.                 return false;
  132.         }
  133.         $note null;
  134.         $application null;
  135.         if ($subject instanceof Application)
  136.         {
  137.             $application $subject;
  138.         }
  139.         else
  140.         {
  141.             if ($subject instanceof Note)
  142.             {
  143.                 $note $subject;
  144.             }
  145.         }
  146.         switch ($attribute)
  147.         {
  148.             case self::IS_ACTIVE:
  149.                 return true;
  150.             case self::ADD:
  151.                 return $this->canAdd($user$function);
  152.             case self::LISTING:
  153.                 return $this->canList($user$function);
  154.             case self::LISTING_SOCIETY:
  155.                 return $this->canListSociety($user$function);
  156.             case self::LISTING_ANY:
  157.                 return $this->canListAny($user$function);
  158.             case self::VIEW:
  159.                 return $this->canView($application$user$function);
  160.             case self::EDIT:
  161.                 return $this->canEdit($application$user$function);
  162.             case self::DELETE:
  163.                 return $this->canDelete($application$user$function);
  164.             case self::CONVERT:
  165.                 return $this->canConvert($user$function);
  166.             case self::ACCEPT:
  167.                 return $this->canAccept($application);
  168.             case self::REFUSE:
  169.                 return $this->canReject($application);
  170.             case self::ADD_NOTE:
  171.                 return $this->canAddNote($application$user$function);
  172.             case self::EDIT_NOTE:
  173.                 return $this->canEditNote($note$user$function);
  174.             case self::DELETE_NOTE:
  175.                 return $this->canDeleteNote($note$user$function);
  176.         }
  177.         throw new \LogicException('This code should not be reached!');
  178.     }
  179.     // $access is the user trying to load the resource
  180.     // $application is the resource being loaded
  181.     // Check if the Society of the resource
  182.     // belongs to the societies of the $access
  183.     private function checkSociety($objectAccess $access)
  184.     {
  185.         // Get all the societies of the access
  186.         $societies $access->getSocieties();
  187.         // Get the Society of the Application
  188.         $applicationSociety $object->getSociety();
  189.         if ($applicationSociety === null)
  190.             return false;
  191.         $found false;
  192.         foreach ($societies as $society)
  193.         {
  194.             if ($society->getId() == $applicationSociety->getId())
  195.             {
  196.                 $found true;
  197.                 break;
  198.             }
  199.         }
  200.         return $found;
  201.     }
  202.     private function canAdd(Access $userAccessFunction $function)
  203.     {
  204.         // Not allowed for JCAF group
  205.         if ($this->currentGroup->isJcaf())
  206.         {
  207.             return false;
  208.         }
  209.         // Get Acl_Permission
  210.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD);
  211.         if ($aclPerm === null)        return false;
  212.         // Get Acl
  213.         $acl $this->aclRepository->findOneBy(array(
  214.             'function'        =>    $function,
  215.             'permission'    =>    $aclPerm
  216.         ));
  217.         if ($acl === null)        return false;
  218.         // Since only one acl type can exist
  219.         // we can return the result of the acl_permission
  220.         return $acl->getValue();
  221.     }
  222.     private function canList(Access $userAccessFunction $function)
  223.     {
  224.         // Get Acl_Permission
  225.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  226.         if ($aclPerm === null)        return false;
  227.         // Get Acl
  228.         $acl $this->aclRepository->findOneBy(array(
  229.             'function'        =>    $function,
  230.             'permission'    =>    $aclPerm
  231.         ));
  232.         if ($acl === null)        return false;
  233.         // Since only one acl type can exist
  234.         // we can return the result of the acl_permission
  235.         return $acl->getValue();
  236.     }
  237.     private function canListSociety(Access $userAccessFunction $function)
  238.     {
  239.         // Get Acl_Permission
  240.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  241.         if ($aclPerm === null)        return false;
  242.         // Get Acl
  243.         $acl $this->aclRepository->findOneBy(array(
  244.             'function'        =>    $function,
  245.             'permission'    =>    $aclPerm
  246.         ));
  247.         if ($acl === null)        return false;
  248.         // Since only one acl type can exist
  249.         // we can return the result of the acl_permission
  250.         // Further filtering is done in the Controller
  251.         return $acl->getValue();
  252.     }
  253.     private function canListAny(Access $userAccessFunction $function)
  254.     {
  255.         // Two Acl_Permission may exist
  256.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  257.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  258.         // If all are null, exit
  259.         if ($aclPerm === null && $aclPermSociety === null)
  260.             return false;
  261.         // Get First one
  262.         if ($aclPerm !== null)
  263.         {
  264.             $acl $this->aclRepository->findOneBy(array(
  265.                 'function'        =>    $function,
  266.                 'permission'    =>    $aclPerm
  267.             ));
  268.             if ($acl !== null)
  269.             {
  270.                 if ($acl->getValue())
  271.                 {
  272.                     // A single positive answer is enough
  273.                     return true;
  274.                 }
  275.             }
  276.         }
  277.         // If we are here it means that nothing good has been found
  278.         // Load second permission
  279.         if ($aclPermSociety !== null)
  280.         {
  281.             $acl $this->aclRepository->findOneBy(array(
  282.                 'function'        =>    $function,
  283.                 'permission'    =>    $aclPermSociety
  284.             ));
  285.             if ($acl !== null)
  286.             {
  287.                 if ($acl->getValue())
  288.                 {
  289.                     // A single positive answer is enough
  290.                     return true;
  291.                 }
  292.             }
  293.         }
  294.         // If we are here, all hope is lost
  295.         return false;
  296.     }
  297.     private function canView(Application $applicationAccess $userAccessFunction $function)
  298.     {
  299.         // Get Acl_Permissions
  300.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW);
  301.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_SOCIETY);
  302.         // If all are null, exit
  303.         if ($aclPerm === null && $aclPermSociety === null)
  304.             return false;
  305.         // Get First one
  306.         if ($aclPerm !== null)
  307.         {
  308.             $acl $this->aclRepository->findOneBy(array(
  309.                 'function'        =>    $function,
  310.                 'permission'    =>    $aclPerm
  311.             ));
  312.             if ($acl !== null)
  313.             {
  314.                 if ($acl->getValue())
  315.                 {
  316.                     // A single positive answer is enough
  317.                     return true;
  318.                 }
  319.             }
  320.         }
  321.         // If we are here it means that nothing good has been found
  322.         // Load second permission
  323.         if ($aclPermSociety !== null)
  324.         {
  325.             $acl $this->aclRepository->findOneBy(array(
  326.                 'function'        =>    $function,
  327.                 'permission'    =>    $aclPermSociety
  328.             ));
  329.             if ($acl !== null)
  330.             {
  331.                 if ($acl->getValue())
  332.                 {
  333.                     // A single positive answer is enough
  334.                     // In this case the good answer will be provided by the checkSociety
  335.                     return $this->checkSociety($application$user);
  336.                 }
  337.             }
  338.         }
  339.         // If we are here, all hope is lost
  340.         return false;
  341.     }
  342.     private function canEdit(Application $applicationAccess $userAccessFunction $function)
  343.     {
  344.         // No editing of applications that have been accepted or refused
  345.         if ($application->isAcceptedOrRejected())
  346.         {
  347.             return false;
  348.         }
  349.         // Three Acl_Permission may exist
  350.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  351.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_SOCIETY);
  352.         // If all are null, exit
  353.         if ($aclPerm === null && $aclPermSociety === null)
  354.             return false;
  355.         // Get First one
  356.         if ($aclPerm !== null)
  357.         {
  358.             $acl $this->aclRepository->findOneBy(array(
  359.                 'function'        =>    $function,
  360.                 'permission'    =>    $aclPerm
  361.             ));
  362.             if ($acl !== null)
  363.             {
  364.                 if ($acl->getValue())
  365.                 {
  366.                     // A single positive answer is enough
  367.                     return true;
  368.                 }
  369.             }
  370.         }
  371.         // If we are here it means that nothing good has been found
  372.         // Load second permission
  373.         if ($aclPermSociety !== null)
  374.         {
  375.             $acl $this->aclRepository->findOneBy(array(
  376.                 'function'        =>    $function,
  377.                 'permission'    =>    $aclPermSociety
  378.             ));
  379.             if ($acl !== null)
  380.             {
  381.                 if ($acl->getValue())
  382.                 {
  383.                     // A single positive answer is enough
  384.                     // In this case the good answer will be provided by the checkSociety
  385.                     return $this->checkSociety($application$user);
  386.                 }
  387.             }
  388.         }
  389.         // If we are here, all hope is lost
  390.         return false;
  391.     }
  392.     private function canDelete(Application $applicationAccess $userAccessFunction $function)
  393.     {
  394.         // Not allowed for JCAF group
  395.         if ($this->currentGroup->isJcaf())
  396.         {
  397.             return false;
  398.         }
  399.         // Three Acl_Permission may exist
  400.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE);
  401.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE_SOCIETY);
  402.         // If all are null, exit
  403.         if ($aclPerm === null && $aclPermSociety === null)
  404.             return false;
  405.         // Get First one
  406.         if ($aclPerm !== null)
  407.         {
  408.             $acl $this->aclRepository->findOneBy(array(
  409.                 'function'        =>    $function,
  410.                 'permission'    =>    $aclPerm
  411.             ));
  412.             if ($acl !== null)
  413.             {
  414.                 if ($acl->getValue())
  415.                 {
  416.                     // A single positive answer is enough
  417.                     return true;
  418.                 }
  419.             }
  420.         }
  421.         // If we are here it means that nothing good has been found
  422.         // Load second permission
  423.         if ($aclPermSociety !== null)
  424.         {
  425.             $acl $this->aclRepository->findOneBy(array(
  426.                 'function'        =>    $function,
  427.                 'permission'    =>    $aclPermSociety
  428.             ));
  429.             if ($acl !== null)
  430.             {
  431.                 if ($acl->getValue())
  432.                 {
  433.                     // A single positive answer is enough
  434.                     // In this case the good answer will be provided by the checkSociety
  435.                     return $this->checkSociety($application$user);
  436.                 }
  437.             }
  438.         }
  439.         // If we are here, all hope is lost
  440.         return false;
  441.     }
  442.     private function canConvert(Access $userAccessFunction $function)
  443.     {
  444.         // Not allowed for JCAF group
  445.         if ($this->currentGroup->isJcaf())
  446.         {
  447.             return false;
  448.         }
  449.         // We can only convert an application if the human resource module is activated
  450.         // HumanResource Module activated ?
  451.         if ($this->moduleTools->isInactiveByCode($this->currentGroupModule::MODULE_HUMAN_RESOURCE))
  452.         {
  453.             return false;
  454.         }
  455.         // Get Acl_Permission
  456.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_CONVERT);
  457.         if ($aclPerm === null)        return false;
  458.         // Get Acl
  459.         $acl $this->aclRepository->findOneBy(array(
  460.             'function'        =>    $function,
  461.             'permission'    =>    $aclPerm
  462.         ));
  463.         if ($acl === null)        return false;
  464.         // Since only one acl type can exist
  465.         // we can return the result of the acl_permission
  466.         return $acl->getValue();
  467.     }
  468.     private function canAddNote(Application $applicationAccess $userAccessFunction $function)
  469.     {
  470.         // Three Acl_Permission may exist
  471.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD_NOTE);
  472.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD_NOTE_SOCIETY);
  473.         // If all are null, exit
  474.         if ($aclPerm === null && $aclPermSociety === null)
  475.             return false;
  476.         // Get First one
  477.         if ($aclPerm !== null)
  478.         {
  479.             $acl $this->aclRepository->findOneBy(array(
  480.                 'function'        =>    $function,
  481.                 'permission'    =>    $aclPerm
  482.             ));
  483.             if ($acl !== null)
  484.             {
  485.                 if ($acl->getValue())
  486.                 {
  487.                     // A single positive answer is enough
  488.                     return true;
  489.                 }
  490.             }
  491.         }
  492.         // If we are here it means that nothing good has been found
  493.         // Load second permission
  494.         if ($aclPermSociety !== null)
  495.         {
  496.             $acl $this->aclRepository->findOneBy(array(
  497.                 'function'        =>    $function,
  498.                 'permission'    =>    $aclPermSociety
  499.             ));
  500.             if ($acl !== null)
  501.             {
  502.                 if ($acl->getValue())
  503.                 {
  504.                     // A single positive answer is enough
  505.                     // In this case the good answer will be provided by the checkSociety
  506.                     return $this->checkSociety($application$user);
  507.                 }
  508.             }
  509.         }
  510.         // If we are here, all hope is lost
  511.         return false;
  512.     }
  513.     private function canEditNote(Note $noteAccess $userAccessFunction $function)
  514.     {
  515.         // Allow editing own notes
  516.         if ($user->equals($note->getAuthor()))
  517.         {
  518.             return true;
  519.         }
  520.         // Three Acl_Permission may exist
  521.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_NOTE);
  522.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_NOTE_SOCIETY);
  523.         // If all are null, exit
  524.         if ($aclPerm === null && $aclPermSociety === null)
  525.             return false;
  526.         // Get First one
  527.         if ($aclPerm !== null)
  528.         {
  529.             $acl $this->aclRepository->findOneBy(array(
  530.                 'function'        =>    $function,
  531.                 'permission'    =>    $aclPerm
  532.             ));
  533.             if ($acl !== null)
  534.             {
  535.                 if ($acl->getValue())
  536.                 {
  537.                     // A single positive answer is enough
  538.                     return true;
  539.                 }
  540.             }
  541.         }
  542.         // If we are here it means that nothing good has been found
  543.         // Load second permission
  544.         if ($aclPermSociety !== null)
  545.         {
  546.             $acl $this->aclRepository->findOneBy(array(
  547.                 'function'        =>    $function,
  548.                 'permission'    =>    $aclPermSociety
  549.             ));
  550.             if ($acl !== null)
  551.             {
  552.                 if ($acl->getValue())
  553.                 {
  554.                     // A single positive answer is enough
  555.                     // In this case the good answer will be provided by the checkSociety
  556.                     return $this->checkSociety($note$user);
  557.                 }
  558.             }
  559.         }
  560.         // If we are here, all hope is lost
  561.         return false;
  562.     }
  563.     private function canDeleteNote(Note $noteAccess $userAccessFunction $function)
  564.     {
  565.         // Allow deleting own notes
  566.         if ($user->equals($note->getAuthor()))
  567.         {
  568.             return true;
  569.         }
  570.         // Three Acl_Permission may exist
  571.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE_NOTE);
  572.         $aclPermSociety $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE_NOTE_SOCIETY);
  573.         // If all are null, exit
  574.         if ($aclPerm === null && $aclPermSociety === null)
  575.             return false;
  576.         // Get First one
  577.         if ($aclPerm !== null)
  578.         {
  579.             $acl $this->aclRepository->findOneBy(array(
  580.                 'function'        =>    $function,
  581.                 'permission'    =>    $aclPerm
  582.             ));
  583.             if ($acl !== null)
  584.             {
  585.                 if ($acl->getValue())
  586.                 {
  587.                     // A single positive answer is enough
  588.                     return true;
  589.                 }
  590.             }
  591.         }
  592.         // If we are here it means that nothing good has been found
  593.         // Load second permission
  594.         if ($aclPermSociety !== null)
  595.         {
  596.             $acl $this->aclRepository->findOneBy(array(
  597.                 'function'        =>    $function,
  598.                 'permission'    =>    $aclPermSociety
  599.             ));
  600.             if ($acl !== null)
  601.             {
  602.                 if ($acl->getValue())
  603.                 {
  604.                     // A single positive answer is enough
  605.                     // In this case the good answer will be provided by the checkSociety
  606.                     return $this->checkSociety($note$user);
  607.                 }
  608.             }
  609.         }
  610.         // If we are here, all hope is lost
  611.         return false;
  612.     }
  613.     private function canAccept(Application $application)
  614.     {
  615.         $societyGroup $application->getSocietyGroup();
  616.         // Application must have a society group
  617.         if ($societyGroup === null)
  618.         {
  619.             return false;
  620.         }
  621.         // Society Group should be Jcaf
  622.         if ($societyGroup->isNotJcaf())
  623.         {
  624.             return false;
  625.         }
  626.         // Application should be not accepted, nor rejected
  627.         if ($application->isAcceptedOrRejected())
  628.         {
  629.             return false;
  630.         }
  631.         // All seems to be good
  632.         return true;
  633.     }
  634.     private function canReject(Application $application)
  635.     {
  636.         $societyGroup $application->getSocietyGroup();
  637.         // Application must have a society group
  638.         if ($societyGroup === null)
  639.         {
  640.             return false;
  641.         }
  642.         // Society Group should be Jcaf
  643.         if ($societyGroup->isNotJcaf())
  644.         {
  645.             return false;
  646.         }
  647.         // Application should be not accepted, nor rejected
  648.         if ($application->isAcceptedOrRejected())
  649.         {
  650.             return false;
  651.         }
  652.         // All seems to be good
  653.         return true;
  654.     }
  655. }