src/Security/TemplateVoter.php line 69

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/TemplateVoter.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\Ikea\TemplateProduct as IkeaTemplateProduct;
  14. use App\Entity\Product\Template;
  15. use App\Entity\Platform\Devis\Devis;
  16. use App\Entity\Platform\Devis\DevisProduct;
  17. use App\Entity\Platform\Invoice\InvoiceProduct;
  18. use App\Entity\Security\Acl;
  19. use App\Entity\Security\AclPermission;
  20. use App\Services\Config\ModuleTools;
  21. class TemplateVoter extends Voter
  22. {
  23.     //--------------------------------------------------------------------------------
  24.     // is_granted constants
  25.     const IS_ACTIVE "template_is_active";
  26.     const ADD "add_template";
  27.     const LISTING "list_templates";
  28.     const VIEW "view_template";
  29.     const EDIT "edit_template";
  30.     const DELETE "delete_template";
  31.     const DELETE_WITH_PRODUCTS "delete_template_and_products";
  32.     // Plan.io Task #4561
  33.     const CHANGE_LINEAR_METERS_USAGE "change_linear_meters_usage";
  34.     const IS_GRANTED_CONSTANTS = array(
  35.         self::IS_ACTIVE,
  36.         self::ADD,
  37.         self::LISTING,
  38.         self::VIEW,
  39.         self::EDIT,
  40.         self::DELETE,
  41.         self::DELETE_WITH_PRODUCTS,
  42.         self::CHANGE_LINEAR_METERS_USAGE,
  43.     );
  44.     //--------------------------------------------------------------------------------
  45.     // acl constants
  46.     const ACL_PERM_ADD "template_add";
  47.     const ACL_PERM_LISTING "template_list";
  48.     const ACL_PERM_VIEW "template_view";
  49.     const ACL_PERM_EDIT "template_edit";
  50.     const ACL_PERM_DELETE "template_delete";
  51.     //--------------------------------------------------------------------------------
  52.     public function __construct(ManagerRegistry $doctrineModuleTools $moduleTools)
  53.     {
  54.         $this->em $doctrine->getManager();
  55.         $this->moduleTools $moduleTools;
  56.         $this->aclRepository $this->em->getRepository(Acl::class);
  57.         $this->aclPermissionRepository $this->em->getRepository(AclPermission::class);
  58.     }
  59.     // Plan.io Task #4453 [See AccessVoter for details]
  60.     public function supportsAttribute(string $attribute): bool
  61.     {
  62.         return in_array($attributeself::IS_GRANTED_CONSTANTStrue);
  63.     }
  64.     
  65.     protected function supports(string $attribute$subject): bool
  66.     {
  67.         // if the attribute isn't one we support, return false
  68.         if (!in_array($attributeself::IS_GRANTED_CONSTANTS))
  69.         {
  70.             return false;
  71.         }
  72.         // only vote on Template objects inside this voter
  73.         if ($subject !== null && !$subject instanceof Template)
  74.         {
  75.             return false;
  76.         }
  77.         return true;
  78.     }
  79.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  80.     {
  81.         $user $token->getUser();
  82.         if (!$user instanceof Access)
  83.         {
  84.             // the user must be logged in; if not, deny access
  85.             return false;
  86.         }
  87.         // The user must have a function; if not deny access
  88.         $function $user->getFunction();
  89.         if ($function === null)        return false;
  90.         // Plan.io Task #3710 : Get current group
  91.         $currentGroup $user->getSocietyGroup();
  92.         if ($currentGroup === null)
  93.             return false;
  94.         // Module activated ?
  95.         // The module is Product, it includes the Templates
  96.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_PRODUCT))
  97.         {
  98.             return false;
  99.         }
  100.         // you know $subject is a Template object, thanks to supports
  101.         /** @var Template $template */
  102.         $template $subject;
  103.         // Check current group affectation
  104.         if ($subject !== null)
  105.         {
  106.             $subjectGroup $subject->getSocietyGroup();
  107.             if ($subjectGroup === null)
  108.                 return false;
  109.             if (!$currentGroup->equals($subjectGroup))
  110.                 return false;
  111.         }
  112.         switch ($attribute)
  113.         {
  114.             case self::IS_ACTIVE:
  115.                 return true;
  116.             case self::ADD:
  117.                 return $this->canAdd($user$function);
  118.             case self::LISTING:
  119.                 return $this->canList($user$function);
  120.             case self::VIEW:
  121.                 return $this->canView($template$user$function);
  122.             case self::EDIT:
  123.                 return $this->canEdit($template$user$function);
  124.             case self::DELETE:
  125.                 return $this->canDelete($template$user$function);
  126.             case self::DELETE_WITH_PRODUCTS:
  127.                 return $this->canDeleteWithProducts($template$user$function);
  128.             case self::CHANGE_LINEAR_METERS_USAGE:
  129.                 return $this->canChangeLinearMetersUsage($template$user$function);
  130.         }
  131.         throw new \LogicException('This code should not be reached!');
  132.     }
  133.     private function canChangeLinearMetersUsage(Template $templateAccess $accessAccessFunction $function)
  134.     {
  135.         // If the template has an associated Method Ikea Template => Deny
  136.         $ikeaTemplates $this->em->getRepository(IkeaTemplateProduct::class)
  137.             ->getIkeaTemplatesForPlatformTemplate($template);
  138.         if (!empty($ikeaTemplates))
  139.         {
  140.             foreach ($ikeaTemplates as $ikeaTemplate
  141.             {
  142.                 if ($ikeaTemplate->isMethod())
  143.                 {
  144.                     return false;
  145.                 }
  146.             }
  147.         }
  148.         // At least one Devis exists ?
  149.         $devis $this->em->getRepository(Devis::class)->findOneByTemplate($template);
  150.         if ($devis !== null)
  151.         {
  152.             return false;
  153.         }
  154.         // All looks good => Load normal permissions
  155.         return $this->canEdit($template$access$function);
  156.     }
  157.     private function canAdd(Access $accessAccessFunction $function)
  158.     {
  159.         // Get Acl_Permission
  160.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD);
  161.         if ($aclPerm === null)        return false;
  162.         // Get Acl
  163.         $acl $this->aclRepository->findOneBy(array(
  164.             'function'        =>    $function,
  165.             'permission'    =>    $aclPerm
  166.         ));
  167.         if ($acl === null)        return false;
  168.         return $acl->getValue();
  169.     }
  170.     private function canList(Access $accessAccessFunction $function)
  171.     {
  172.         // Restrictions are also applied in the Controller
  173.         // But this helps speeding page loading if the access is not even allowed to load the page
  174.         // (ie. if it has no list privileges whatsoever)
  175.         // Get Acl_Permission
  176.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  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.         // Since only one list type can exist for the Templates,
  185.         // we can return the result of the acl_permission
  186.         return $acl->getValue();
  187.     }
  188.     private function canView(Template $templateAccess $accessAccessFunction $function)
  189.     {
  190.         // Several Acl_Permission exist
  191.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW);
  192.         // If all are null, exit
  193.         if ($aclPerm === null)
  194.             return false;
  195.         // Get First one (view all)
  196.         if ($aclPerm !== null)
  197.         {
  198.             $acl $this->aclRepository->findOneBy(array(
  199.                 'function'        =>    $function,
  200.                 'permission'    =>    $aclPerm
  201.             ));
  202.             if ($acl !== null)
  203.             {
  204.                 if ($acl->getValue())
  205.                 {
  206.                     // A single positive answer is enough
  207.                     return true;
  208.                 }
  209.             }
  210.         }
  211.         // If we are here, all hope is lost
  212.         return false;
  213.     }
  214.     private function canEdit(Template $templateAccess $accessAccessFunction $function)
  215.     {
  216.         if (!$template->getIsActive())
  217.         {
  218.             return false;
  219.         }
  220.         // Several Acl_Permission exist
  221.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  222.         // If all are null, exit
  223.         if ($aclPerm === null)
  224.             return false;
  225.         // Get First one (view all)
  226.         if ($aclPerm !== null)
  227.         {
  228.             $acl $this->aclRepository->findOneBy(array(
  229.                 'function'        =>    $function,
  230.                 'permission'    =>    $aclPerm
  231.             ));
  232.             if ($acl !== null)
  233.             {
  234.                 if ($acl->getValue())
  235.                 {
  236.                     // A single positive answer is enough
  237.                     return true;
  238.                 }
  239.             }
  240.         }
  241.         // If we are here, all hope is lost
  242.         return false;
  243.     }
  244.     private function canDelete(Template $templateAccess $accessAccessFunction $function)
  245.     {
  246.         // Do not allow deleting if in use
  247.         $devis $this->em->getRepository(Devis::class)->findOneByTemplate($template);
  248.         if ($devis !== null)
  249.             return false;
  250.         // Several Acl_Permission exist
  251.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE);
  252.         // If all are null, exit
  253.         if ($aclPerm === null)
  254.             return false;
  255.         // Get First one (view all)
  256.         if ($aclPerm !== null)
  257.         {
  258.             $acl $this->aclRepository->findOneBy(array(
  259.                 'function'        =>    $function,
  260.                 'permission'    =>    $aclPerm
  261.             ));
  262.             if ($acl !== null)
  263.             {
  264.                 if ($acl->getValue())
  265.                 {
  266.                     // A single positive answer is enough
  267.                     return true;
  268.                 }
  269.             }
  270.         }
  271.         // If we are here, all hope is lost
  272.         return false;
  273.     }
  274.     private function canDeleteWithProducts(Template $templateAccess $accessAccessFunction $function)
  275.     {
  276.         // Do not allow deleting if in use
  277.         $devis $this->em->getRepository(Devis::class)->findOneByTemplate($template);
  278.         if ($devis !== null)
  279.             return false;
  280.         // Do not allow deleting products if at least one is in use
  281.         foreach ($template->getProducts() as $product
  282.         {
  283.             $devisProduct $this->em->getRepository(DevisProduct::class)->findOneByOriginalProduct($product);
  284.             if ($devisProduct !== null)
  285.                 return false;
  286.             $invoiceProduct $this->em->getRepository(InvoiceProduct::class)->findOneByOriginalProduct($product);
  287.             if ($invoiceProduct !== null)
  288.                 return false;
  289.         }
  290.         // Several Acl_Permission exist
  291.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE);
  292.         // If all are null, exit
  293.         if ($aclPerm === null)
  294.             return false;
  295.         // Get First one (view all)
  296.         if ($aclPerm !== null)
  297.         {
  298.             $acl $this->aclRepository->findOneBy(array(
  299.                 'function'        =>    $function,
  300.                 'permission'    =>    $aclPerm
  301.             ));
  302.             if ($acl !== null)
  303.             {
  304.                 if ($acl->getValue())
  305.                 {
  306.                     // A single positive answer is enough
  307.                     return true;
  308.                 }
  309.             }
  310.         }
  311.         // If we are here, all hope is lost
  312.         return false;
  313.     }
  314. }