src/Security/ProductVoter.php line 25

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/ProductVoter.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\APIRest\AccessAPI;
  11. use App\Entity\Config\Config;
  12. use App\Entity\Config\Module;
  13. use App\Entity\HR\AccessFunction;
  14. use App\Entity\Product\Charge;
  15. use App\Entity\Product\Product;
  16. use App\Entity\Security\Acl;
  17. use App\Entity\Security\AclPermission;
  18. use App\Services\LogTools;
  19. use App\Services\Config\ModuleTools;
  20. use App\Services\Config\OptionConfigTools;
  21. class ProductVoter extends Voter
  22. {
  23.     //--------------------------------------------------------------------------------
  24.     // is_granted constants
  25.     const IS_ACTIVE "product_is_active";
  26.     const IS_ACTIVE_ECO_BONUS "eco_bonus_is_active";    // #4328
  27.     const ADD "add_product";
  28.     const LISTING "list_products";
  29.     const VIEW "view_product";
  30.     const EDIT "edit_product";
  31.     const DELETE "delete_product";
  32.     const IMPORT "import_products";
  33.     // Plan.io Task #3605
  34.     const EDIT_GHOST_PARAMS "edit_product_ghost_params";
  35.     const IS_GRANTED_CONSTANTS = array(
  36.         self::IS_ACTIVE,
  37.         self::IS_ACTIVE_ECO_BONUS,
  38.         self::ADD,
  39.         self::LISTING,
  40.         self::VIEW,
  41.         self::EDIT,
  42.         self::DELETE,
  43.         self::IMPORT,
  44.         // Plan.io Task #3605
  45.         self::EDIT_GHOST_PARAMS,
  46.     );
  47.     //--------------------------------------------------------------------------------
  48.     // acl constants
  49.     const ACL_PERM_ADD "product_add";
  50.     const ACL_PERM_LISTING "product_list";
  51.     const ACL_PERM_VIEW "product_view";
  52.     const ACL_PERM_EDIT "product_edit";
  53.     const ACL_PERM_DELETE "product_delete";
  54.     const ACL_PERM_IMPORT "product_import";
  55.     //--------------------------------------------------------------------------------
  56.     public function __construct(ManagerRegistry $doctrineModuleTools $moduleToolsOptionConfigTools $optionConfigToolsLogTools $logTools)
  57.     {
  58.         $this->em $doctrine->getManager();
  59.         $this->moduleTools $moduleTools;
  60.         $this->optionConfigTools $optionConfigTools;
  61.         $this->logTools $logTools;
  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 Product objects inside this voter
  78.         if ($subject !== null && (!$subject instanceof Product && !$subject instanceof Charge))
  79.         {
  80.             return false;
  81.         }
  82.         return true;
  83.     }
  84.     protected function voteOnAttribute(string $attribute$subjectTokenInterface $token): bool
  85.     {
  86.         $user $token->getUser();
  87.         // Plan.io Task #3707
  88.         if ($user instanceof AccessAPI)
  89.         {
  90.             if ($user->getAccess() === null)
  91.             {
  92.                 return false;
  93.             }
  94.             $user $user->getAccess();
  95.         }
  96.         if (!$user instanceof Access)
  97.         {
  98.             // the user must be logged in; if not, deny access
  99.             return false;
  100.         }
  101.         // The user must have a function; if not deny access
  102.         $function $user->getFunction();
  103.         if ($function === null)        return false;
  104.         // Plan.io Task #3710 : Get current group
  105.         $currentGroup $user->getSocietyGroup();
  106.         if ($currentGroup === null)
  107.             return false;
  108.         // Plan.io Task #3605
  109.         $this->currentGroup $currentGroup;
  110.         // Module activated ?
  111.         if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_PRODUCT))
  112.         {
  113.             return false;
  114.         }
  115.         // Check current group affectation
  116.         if ($subject !== null)
  117.         {
  118.             $subjectGroup $subject->getSocietyGroup();
  119.             if ($subjectGroup === null)
  120.                 return false;
  121.             if (!$currentGroup->equals($subjectGroup))
  122.                 return false;
  123.         }
  124.         switch ($attribute)
  125.         {
  126.             case self::IS_ACTIVE:
  127.                 return true;
  128.             case self::IS_ACTIVE_ECO_BONUS:
  129.             {
  130.                 if ($this->moduleTools->isInactiveByCode($currentGroupModule::MODULE_ECO_BONUS))
  131.                 {
  132.                     return false;
  133.                 }
  134.                 return true;
  135.             }
  136.             case self::IMPORT:
  137.                 return $this->canImport($user$function);
  138.             case self::ADD:
  139.                 return $this->canAdd($user$function);
  140.             case self::LISTING:
  141.                 return $this->canList($user$function);
  142.             case self::VIEW:
  143.                 return $this->canView($user$function);
  144.             case self::EDIT:
  145.                 return $this->canEdit($subject$user$function);
  146.             case self::DELETE:
  147.                 return $this->canDelete($subject$user$function);
  148.             // Plan.io task #3605
  149.             case self::EDIT_GHOST_PARAMS:
  150.             {
  151.                 if ($subject instanceof Charge)
  152.                 {
  153.                     return false;
  154.                 }
  155.                 return $this->canEditGhostParams($subject$user$function);
  156.             }
  157.         }
  158.         throw new \LogicException('This code should not be reached!');
  159.     }
  160.     private function canImport(Access $accessAccessFunction $function)
  161.     {
  162.         // Get Acl_Permission
  163.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_IMPORT);
  164.         if ($aclPerm === null)        return false;
  165.         // Get Acl
  166.         $acl $this->aclRepository->findOneBy(array(
  167.             'function'        =>    $function,
  168.             'permission'    =>    $aclPerm
  169.         ));
  170.         if ($acl === null)        return false;
  171.         return $acl->getValue();
  172.     }
  173.     private function canAdd(Access $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(Access $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 Products,
  201.         // we can return the result of the acl_permission
  202.         return $acl->getValue();
  203.     }
  204.     private function canView(Access $accessAccessFunction $function)
  205.     {
  206.         // Several Acl_Permission exist
  207.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW);
  208.         // If all are null, exit
  209.         if ($aclPerm === null)
  210.             return false;
  211.         // Get First one (view all)
  212.         if ($aclPerm !== null)
  213.         {
  214.             $acl $this->aclRepository->findOneBy(array(
  215.                 'function'        =>    $function,
  216.                 'permission'    =>    $aclPerm
  217.             ));
  218.             if ($acl !== null)
  219.             {
  220.                 if ($acl->getValue())
  221.                 {
  222.                     // A single positive answer is enough
  223.                     return true;
  224.                 }
  225.             }
  226.         }
  227.         // If we are here, all hope is lost
  228.         return false;
  229.     }
  230.     private function canEdit(Product|Charge $subjectAccess $accessAccessFunction $function)
  231.     {
  232.         // Do not allow editing the free product
  233.         if ($subject instanceof Product)
  234.         {
  235.             if ($subject->isFree())
  236.             {
  237.                 return false;
  238.             }
  239.         }
  240.         // Several Acl_Permission exist
  241.         $aclPerm $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  242.         // If all are null, exit
  243.         if ($aclPerm === null)
  244.             return false;
  245.         // Get First one (view all)
  246.         if ($aclPerm !== null)
  247.         {
  248.             $acl $this->aclRepository->findOneBy(array(
  249.                 'function'        =>    $function,
  250.                 'permission'    =>    $aclPerm
  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.     // Plan.io task #3605
  265.     private function canEditGhostParams(Product $productAccess $accessAccessFunction $function)
  266.     {
  267.         // Deny on discounts
  268.         if ($product->isDiscount())
  269.         {
  270.             return false;
  271.         }
  272.         // Check OptionConfig
  273.         if (!$this->optionConfigTools->isActive_GhostInvoicing($this->currentGroup))
  274.         {
  275.             return false;
  276.         }
  277.         // Finally check edit permissions
  278.         return $this->canEdit($product$access$function);
  279.     }
  280.     private function canDelete(Product|Charge $subjectAccess $accessAccessFunction $function)
  281.     {
  282.         // Do not allow editing the free product
  283.         if ($subject instanceof Product)
  284.         {
  285.             if ($subject->isFree())
  286.             {
  287.                 return false;
  288.             }
  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. }