src/Security/ProjectManagerVoter.php line 68

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/ProjectManagerVoter.php
  4. //------------------------------------------------------------------------------
  5. namespace App\Security;
  6. use Doctrine\Persistence\ManagerRegistry;
  7. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  8. use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
  9. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  10. use App\Entity\Access;
  11. use App\Entity\APIRest\AccessAPI;
  12. use App\Entity\Config\Module;
  13. use App\Entity\HR\AccessFunction;
  14. use App\Entity\Mission\Mission;
  15. use App\Entity\ProjectManager\Blueprint;
  16. use App\Entity\ProjectManager\BlueprintPdf;
  17. use App\Entity\ProjectManager\ProjectNotebook;
  18. use App\Entity\Security\Acl;
  19. use App\Entity\Security\AclPermission;
  20. use App\Services\Config\ModuleTools;
  21. class ProjectManagerVoter extends Voter
  22. {
  23.     const IS_ACTIVE "project_manager_is_active";    
  24.     const CAN_ACCESS "can_access_project_manager";
  25.     const LIST = "list_project_manager_notebooks";
  26.     
  27.     const VIEW_PDF_CLIENT "view_project_manager_notebook_pdf_client";
  28.     const VIEW_PDF_IKEA "view_project_manager_notebook_pdf_ikea";
  29.     const VIEW_PDF_INSTALLER "view_project_manager_notebook_pdf_installer";    
  30.     
  31.     const DELETE "delete_project_manager_notebook";
  32.     
  33.     // Same as CAN_ACCESS if mission !== null
  34.     // If mission === null checks isGranted('rekapp_admin')
  35.     const DELETE_KP "delete_kitchen_planner_project";
  36.     const IS_GRANTED_CONSTANTS = array(
  37.         self::IS_ACTIVE,
  38.         self::CAN_ACCESS,    
  39.         self::VIEW_PDF_CLIENT,        
  40.         self::VIEW_PDF_IKEA,        
  41.         self::VIEW_PDF_INSTALLER,                
  42.         
  43.         self::LIST,        
  44.         self::DELETE,        
  45.         self::DELETE_KP,        
  46.     );
  47.     //--------------------------------------------------------------------------------
  48.     // acl constants
  49.     //--------------------------------------------------------------------------------
  50.     const ACL_PERM_CAN_ACCESS "project_manager_can_access";
  51.     const ACL_PERM_LIST "project_manager_notebook_list";
  52.     
  53.     const ACL_PERM_VIEW_PDF_CLIENT "project_manager_notebook_view_pdf_client";
  54.     const ACL_PERM_VIEW_PDF_IKEA "project_manager_notebook_view_pdf_ikea";
  55.     const ACL_PERM_VIEW_PDF_INSTALLER "project_manager_notebook_view_pdf_installer";    
  56.     public function __construct(AccessDecisionManagerInterface $accessDecisionManagerManagerRegistry $doctrine,
  57.         ModuleTools $moduleTools)
  58.     {
  59.         $this->accessDecisionManager $accessDecisionManager;
  60.         $this->em $doctrine->getManager();
  61.         $this->moduleTools $moduleTools;
  62.         $this->aclRepository $this->em->getRepository(Acl::class);
  63.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  64.     }
  65.     // Plan.io Task #4453 [See AccessVoter for details]
  66.     public function supportsAttribute(string $attribute): bool
  67.     {
  68.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  69.     }
  70.     protected function supports(string $attribute$subject): bool
  71.     {
  72.         // if the attribute isn't one we support, return false
  73.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  74.         {
  75.             return false;
  76.         }
  77.         // only vote on Mission|ProjectNotebook objects inside this voter
  78.         if ($subject !== null && !$subject instanceof Mission && !$subject instanceof ProjectNotebook)
  79.         {
  80.             return false;
  81.         }
  82.         return true;
  83.     }
  84.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  85.     {
  86.         $user $token->getUser();
  87.         $originalUserIsAccess true;
  88.         // Plan.io Task #3707
  89.         if ($user instanceof AccessAPI)
  90.         {
  91.             if ($user->getAccess() === null)
  92.             {
  93.                 return false;
  94.             }
  95.             $user $user->getAccess();
  96.             $originalUserIsAccess false;
  97.         }
  98.         // Plan.io Task #3707
  99.         // At this point $user is an object of Access type
  100.         // even if the $token->getUser() is AccessAPI
  101.         if (!$user instanceof Access)
  102.         {
  103.             // the user must be logged in; if not, deny access
  104.             return false;
  105.         }
  106.         // The user must have a function; if not deny access
  107.         $function $user->getFunction();
  108.         if ($function === null)        return false;
  109.         // Plan.io Task #3710 : Get current group
  110.         $currentGroup $user->getSocietyGroup();
  111.         if ($currentGroup === null)
  112.             return false;
  113.         $this->currentGroup $currentGroup;
  114.         // Module activated ?
  115.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_PROJECT_MANAGER))
  116.         {
  117.             return false;
  118.         }        
  119.         $mission null;
  120.         $notebook null;
  121.         $subjectGroup null;
  122.         if ($subject !== null)
  123.         {
  124.             if ($subject instanceof Mission)
  125.             {
  126.                 $mission $subject;
  127.                 $notebook $mission->getProjectNotebook();
  128.                 $subjectGroup $mission->getSocietyGroupAuthor();
  129.             }
  130.             elseif ($subject instanceof ProjectNotebook)
  131.             {
  132.                 $mission $subject->getMission();
  133.                 $notebook $subject;
  134.                 $subjectGroup $notebook->getSocietyGroup();
  135.             }
  136.         }
  137.         // Deny for shared missions for now
  138.         if ($mission !== null && $mission->isShared())
  139.         {
  140.             return false;
  141.         }
  142.         // Check current group affectation
  143.         if ($subjectGroup !== null)
  144.         {            
  145.             if (!$currentGroup->equals($subjectGroup))
  146.             {
  147.                 return false;
  148.             }
  149.         }        
  150.         switch ($attribute)
  151.         {
  152.             case self::IS_ACTIVE:
  153.                 return true;
  154.             case self::CAN_ACCESS:
  155.                 return $this->canAccess($mission$user$function);
  156.             case self::LIST:
  157.                 return $this->canList($user$function);
  158.             case self::VIEW_PDF_CLIENT:
  159.             {
  160.                 if ($mission === null || $notebook === null)
  161.                 {
  162.                     return false;
  163.                 }
  164.                 return $this->canViewPdf($mission$notebook$user$function$tokenBlueprintPdf::pdf_type_client);
  165.             }
  166.             case self::VIEW_PDF_IKEA:
  167.             {
  168.                 if ($mission === null || $notebook === null)
  169.                 {
  170.                     return false;
  171.                 }
  172.                 return $this->canViewPdf($mission$notebook$user$function$tokenBlueprintPdf::pdf_type_ikea);
  173.             }
  174.             
  175.             case self::VIEW_PDF_INSTALLER:
  176.             {
  177.                 if ($mission === null || $notebook === null)
  178.                 {
  179.                     return false;
  180.                 }
  181.                 return $this->canViewPdf($mission$notebook$user$function$tokenBlueprintPdf::pdf_type_installer);
  182.             }
  183.             
  184.             case self::DELETE:
  185.                 return $this->canDelete($token);
  186.             
  187.             case self::DELETE_KP:
  188.                 return $this->canDeleteKp($mission$user$function$token);
  189.         }
  190.         throw new \LogicException('This code should not be reached!');
  191.     }
  192.     private function canAccess(?Mission $missionAccess $userAccessFunction $function)
  193.     {
  194.         if ($mission === null)
  195.         {
  196.             // This should not happen
  197.             return false;
  198.         }        
  199.         // Get AclPermission
  200.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_CAN_ACCESS);
  201.         if ($aclPerm === null)        return false;
  202.         // Get Acl
  203.         $acl $this->aclRepository->findOneBy(array(
  204.             'function'        =>    $function,
  205.             'permission'    =>    $aclPerm
  206.         ));
  207.         if ($acl === null)        return false;
  208.         // Since only one acl type can exist
  209.         // we can return the result of the acl_permission
  210.         return $acl->getValue();
  211.         
  212.         // If we are here, all hope is lost
  213.         return false;
  214.     }
  215.     private function canList(Access $userAccessFunction $function)
  216.     {
  217.         // Get AclPermission
  218.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LIST);
  219.         if ($aclPerm === null)        return false;
  220.         // Get Acl
  221.         $acl $this->aclRepository->findOneBy(array(
  222.             'function'        =>    $function,
  223.             'permission'    =>    $aclPerm
  224.         ));
  225.         if ($acl === null)        return false;
  226.         // Since only one acl type can exist
  227.         // we can return the result of the acl_permission
  228.         return $acl->getValue();
  229.         
  230.         // If we are here, all hope is lost
  231.         return false;
  232.     }
  233.     private function canViewPdf(Mission $missionProjectNotebook $projectNotebookAccess $userAccessFunction $function$token$type)
  234.     {
  235.         // If the user can access the ProjectManager => It can view the PDFs
  236.         if ($this->canAccess($mission$user$function))
  237.         {
  238.             return true;
  239.         }
  240.         // If the user can access the Mission => It can view the PDFs
  241.         $mission $projectNotebook->getMission();
  242.         if ($this->accessDecisionManager->decide($token, ['view_mission'], $mission))
  243.         {
  244.             return true;
  245.         }
  246.         // Load correct permission based on type
  247.         switch ($type) {
  248.             case BlueprintPdf::pdf_type_client:
  249.                 $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_PDF_CLIENT);
  250.                 break;
  251.             case BlueprintPdf::pdf_type_ikea:
  252.                 $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_PDF_IKEA);
  253.                 break;
  254.             case BlueprintPdf::pdf_type_installer:
  255.                 $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_PDF_INSTALLER);
  256.                 break;
  257.             
  258.             default:
  259.                 return false;
  260.                 break;
  261.         }    
  262.         
  263.         // If all are null, exit
  264.         if ($aclPerm === null)
  265.             return false;
  266.         // Get First one
  267.         if ($aclPerm !== null)
  268.         {
  269.             $acl $this->aclRepository->findOneBy(array(
  270.                 'function'        =>    $function,
  271.                 'permission'    =>    $aclPerm
  272.             ));
  273.             if ($acl !== null)
  274.             {
  275.                 if ($acl->getValue())
  276.                 {
  277.                     // A single positive answer is enough
  278.                     return true;
  279.                 }
  280.             }
  281.         }
  282.         // If we are here, all hope is lost
  283.         return false;
  284.     }
  285.     private function canDelete($token)
  286.     {
  287.         return $this->accessDecisionManager->decide($token, ['rekapp_admin']);
  288.     }
  289.     private function canDeleteKp(?Mission $missionAccess $userAccessFunction $function$token)
  290.     {
  291.         if ($mission === null)
  292.         {
  293.             // This should not happen
  294.             return $this->accessDecisionManager->decide($token, ['rekapp_admin']);
  295.         }
  296.         
  297.         return $this->canAccess($mission$user$function);
  298.     }
  299. }