src/Security/CostVoter.php line 116

Open in your IDE?
  1. <?php
  2. //------------------------------------------------------------------------------
  3. // src/Security/CostVoter.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\Platform\Cost\Cost;
  15. use App\Entity\Platform\Cost\CostNote;
  16. use App\Entity\Security\Acl;
  17. use App\Entity\Security\AclPermission;
  18. use App\Services\LogTools;
  19. use App\Services\Config\OptionConfigTools;
  20. use App\Services\Config\ModuleTools;
  21. class CostVoter extends Voter
  22. {
  23.     //--------------------------------------------------------------------------------
  24.     // is_granted constants
  25.     const IS_ACTIVE = "cost_is_active";
  26.     const ADD = "add_cost";
  27.     const ADD_FOR_OTHERS = "add_cost_for_others";
  28.     const ADD_WITH_EDITABLE_STATUS = "add_cost_with_editable_status";
  29.     // Plan.io Task #4507
  30.     const ADD_COST_VENDOR_INVOICE = "add_cost_vendor_invoice";
  31.     const LISTING = "list_costs";
  32.     const LISTING_SOCIETY = "list_costs_society";
  33.     const LISTING_OWN = "list_costs_own";
  34.     const LISTING_ANY = "list_costs_any";
  35.     const VIEW = "view_cost";
  36.     const EDIT = "edit_cost";
  37.     const EDIT_STATUS = "edit_cost_status";
  38.     const EDIT_TYPE = "edit_cost_type";
  39.     const DELETE = "delete_cost";
  40.     const SEEN = "mark_seen_cost";
  41.     const ADD_COST_NOTE = "add_cost_note";
  42.     const EDIT_COST_NOTE = "edit_cost_note";
  43.     const DELETE_COST_NOTE = "delete_cost_note";
  44.     // Plan.io Task #4426
  45.     const IS_ACTIVE_COST_AUTO_ACCOUNT = "cost_auto_account_is_active";
  46.     const IS_GRANTED_CONSTANTS = array(
  47.         self::IS_ACTIVE,
  48.         self::ADD,
  49.         self::ADD_FOR_OTHERS,
  50.         self::ADD_WITH_EDITABLE_STATUS,
  51.         self::ADD_COST_VENDOR_INVOICE,
  52.         self::LISTING,
  53.         self::LISTING_SOCIETY,
  54.         self::LISTING_OWN,
  55.         self::LISTING_ANY,
  56.         self::VIEW,
  57.         self::EDIT,
  58.         self::EDIT_STATUS,
  59.         self::EDIT_TYPE,
  60.         self::DELETE,
  61.         self::SEEN,
  62.         self::ADD_COST_NOTE,
  63.         self::EDIT_COST_NOTE,
  64.         self::DELETE_COST_NOTE,
  65.         self::IS_ACTIVE_COST_AUTO_ACCOUNT,
  66.     );
  67.     //--------------------------------------------------------------------------------
  68.     // acl constants
  69.     const ACL_PERM_ADD = "cost_add";
  70.     const ACL_PERM_ADD_FOR_OTHERS = "cost_add_for_others";
  71.     const ACL_PERM_ADD_WITH_EDITABLE_STATUS = "cost_add_with_editable_status";
  72.     
  73.     // Plan.io Task #4507
  74.     const ACL_PERM_ADD_VENDOR_INVOICE = "cost_vendor_invoice_add";
  75.     
  76.     const ACL_PERM_LISTING = "cost_list";
  77.     const ACL_PERM_LISTING_SOCIETY = "cost_list_society";
  78.     const ACL_PERM_LISTING_OWN = "cost_list_own";
  79.     const ACL_PERM_VIEW = "cost_view";
  80.     const ACL_PERM_VIEW_SOCIETY = "cost_view_society";
  81.     const ACL_PERM_VIEW_OWN = "cost_view_own";
  82.     const ACL_PERM_EDIT = "cost_edit";
  83.     const ACL_PERM_EDIT_SOCIETY = "cost_edit_society";
  84.     const ACL_PERM_EDIT_OWN = "cost_edit_own";
  85.     const ACL_PERM_EDIT_STATUS = "cost_edit_status";
  86.     const ACL_PERM_EDIT_STATUS_SOCIETY = "cost_edit_status_society";
  87.     const ACL_PERM_DELETE = "cost_delete";
  88.     const ACL_PERM_DELETE_SOCIETY = "cost_delete_society";
  89.     const ACL_PERM_DELETE_OWN = "cost_delete_own";
  90.     const ACL_PERM_SEEN = "cost_seen";
  91.     //--------------------------------------------------------------------------------
  92.     public function __construct(ManagerRegistry $doctrine, ModuleTools $moduleTools, OptionConfigTools $optionConfigTools, LogTools $logTools)
  93.     {
  94.         $this->em = $doctrine->getManager();
  95.         $this->optionConfigTools = $optionConfigTools;
  96.         $this->moduleTools = $moduleTools;
  97.         $this->logTools = $logTools;
  98.         $this->aclRepository = $this->em->getRepository(Acl::class);
  99.         $this->aclPermissionRepository = $this->em->getRepository(AclPermission::class);
  100.     }
  101.     // Plan.io Task #4453 [See AccessVoter for details]
  102.     public function supportsAttribute(string $attribute): bool
  103.     {
  104.         return in_array($attribute, self::IS_GRANTED_CONSTANTS, true);
  105.     }
  106.     
  107.     protected function supports(string $attribute, $subject = null): bool
  108.     {
  109.         // if the attribute isn't one we support, return false
  110.         if (!in_array($attribute, self::IS_GRANTED_CONSTANTS))
  111.         {
  112.             return false;
  113.         }
  114.         // only vote on Cost objects inside this voter
  115.         if ($subject !== null && (!$subject instanceof Cost && !$subject instanceof CostNote))
  116.         {
  117.             return false;
  118.         }
  119.         return true;
  120.     }
  121.     protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
  122.     {
  123.         $user = $token->getUser();
  124.         // Plan.io Task #3707
  125.         if ($user instanceof AccessAPI)
  126.         {
  127.             if ($user->getAccess() === null)
  128.             {
  129.                 return false;
  130.             }
  131.             $user = $user->getAccess();
  132.         }
  133.         // Plan.io Task #3707
  134.         // At this point $user is an object of Access type
  135.         // even if the $token->getUser() is AccessAPI
  136.         if (!$user instanceof Access)
  137.         {
  138.             // the user must be logged in; if not, deny access
  139.             return false;
  140.         }
  141.         // The user must have a function; if not deny access
  142.         $function = $user->getFunction();
  143.         if ($function === null)        return false;
  144.         // Plan.io Task #3710 : Get current group
  145.         $currentGroup = $user->getSocietyGroup();
  146.         if ($currentGroup === null)
  147.             return false;
  148.         // Module activated ?
  149.         if ($this->moduleTools->isInactiveByCode($currentGroup, Module::MODULE_COST))
  150.         {
  151.             return false;
  152.         }
  153.         // you know $subject is a Cost/CostNote object, thanks to supports
  154.         $costNote = null;
  155.         if ($subject instanceof CostNote)
  156.         {
  157.             /** @var CostNote $costNote */
  158.             $costNote = $subject;
  159.             /** @var Cost $cost */
  160.             $cost = $costNote->getCost();
  161.         }
  162.         else
  163.         {
  164.             /** @var Cost $cost */
  165.             $cost = $subject;
  166.         }
  167.         // Check current group affectation
  168.         if ($subject !== null)
  169.         {
  170.             $subjectSociety = $subject->getSociety();
  171.             if ($subjectSociety === null)
  172.                 return false;
  173.             $subjectGroup = $subjectSociety->getGroup();
  174.             if ($subjectGroup === null)
  175.                 return false;
  176.             if (!$currentGroup->equals($subjectGroup))
  177.                 return false;
  178.         }
  179.         switch ($attribute)
  180.         {
  181.             case self::IS_ACTIVE:
  182.                 return true;
  183.             case self::IS_ACTIVE_COST_AUTO_ACCOUNT:
  184.             {
  185.                 return $this->optionConfigTools->isActive_CostAutoAccount($currentGroup);
  186.             }
  187.             case self::ADD:
  188.                 return $this->canAdd($user, $function);
  189.             case self::ADD_FOR_OTHERS:
  190.                 return $this->canAddForOthers($user, $function);
  191.             case self::ADD_WITH_EDITABLE_STATUS:
  192.                 return $this->canAddWithEditableStatus($user, $function);
  193.             
  194.             // Plan.io Task #4507
  195.             case self::ADD_COST_VENDOR_INVOICE:
  196.                 return $this->canAddVendorInvoice($user, $function);
  197.             case self::LISTING:
  198.                 return $this->canList($user, $function);
  199.             case self::LISTING_SOCIETY:
  200.                 return $this->canListSociety($user, $function);
  201.             case self::LISTING_OWN:
  202.                 return $this->canListOwn($user, $function);
  203.             case self::LISTING_ANY:
  204.                 return $this->canListAny($user, $function);
  205.             case self::VIEW:
  206.                 return $this->canView($cost, $user, $function);
  207.             case self::EDIT:
  208.                 return $this->canEdit($cost, $user, $function);
  209.             case self::EDIT_STATUS:
  210.                 return $this->canEditStatus($cost, $user, $function);
  211.             case self::EDIT_TYPE:
  212.                 return $this->canEditType($cost, $user, $function);
  213.             case self::DELETE:
  214.                 return $this->canDelete($cost, $user, $function);
  215.             case self::SEEN:
  216.                 return $this->canMarkAsSeen($cost, $user, $function);
  217.             case self::ADD_COST_NOTE:
  218.                 return $this->canAddCostNote($cost, $user, $function);
  219.             case self::EDIT_COST_NOTE:
  220.                 return $this->canEditCostNote($costNote, $user, $function);
  221.             case self::DELETE_COST_NOTE:
  222.                 return $this->canDeleteCostNote($costNote, $user, $function);
  223.         }
  224.         throw new \LogicException('This code should not be reached!');
  225.     }
  226.     // $access is the user trying to load the resource
  227.     // $cost is the resource being loaded
  228.     // Check if the Society of the resource
  229.     // belongs to the societies of the $access
  230.     private function checkSociety(Cost $cost, Access $access)
  231.     {
  232.         // Get all the societies of the access
  233.         $societies = $access->getSocieties();
  234.         // Get the Society of the Cost
  235.         $costSociety = $cost->getSociety();
  236.         if ($costSociety === null)
  237.             return false;
  238.         $found = false;
  239.         foreach ($societies as $society)
  240.         {
  241.             if ($society->getId() == $costSociety->getId())
  242.             {
  243.                 $found = true;
  244.                 break;
  245.             }
  246.         }
  247.         return $found;
  248.     }
  249.     // Check if the $access is the manager / author of the $cost
  250.     private function checkOwn(Cost $cost, Access $access)
  251.     {
  252.         // Get author
  253.         $author = $cost->getAuthor();
  254.         if ($author === null)
  255.             return false;
  256.         if ($author->getId() === $access->getId())
  257.             return true;
  258.         // Get access
  259.         $theOne = $cost->getAccess();
  260.         if ($theOne === null)
  261.             return false;
  262.         if ($theOne->getId() === $access->getId())
  263.             return true;
  264.         return false;
  265.     }
  266.     private function canAdd(Access $user, AccessFunction $function)
  267.     {
  268.         // Get Acl_Permission
  269.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD);
  270.         if ($aclPerm === null)        return false;
  271.         // Get Acl
  272.         $acl = $this->aclRepository->findOneBy(array(
  273.             'function'        =>    $function,
  274.             'permission'    =>    $aclPerm
  275.         ));
  276.         if ($acl === null)        return false;
  277.         // Since only one acl type can exist
  278.         // we can return the result of the acl_permission
  279.         return $acl->getValue();
  280.     }
  281.     public function canAddForOthers(Access $user, AccessFunction $function)
  282.     {
  283.         // Get Acl_Permission
  284.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD_FOR_OTHERS);
  285.         if ($aclPerm === null)        return false;
  286.         // Get Acl
  287.         $acl = $this->aclRepository->findOneBy(array(
  288.             'function'        =>    $function,
  289.             'permission'    =>    $aclPerm
  290.         ));
  291.         if ($acl === null)        return false;
  292.         // Since only one acl type can exist
  293.         // we can return the result of the acl_permission
  294.         return $acl->getValue();
  295.     }
  296.     public function canAddWithEditableStatus(Access $user, AccessFunction $function)
  297.     {
  298.         // Get Acl_Permission
  299.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_ADD_WITH_EDITABLE_STATUS);
  300.         if ($aclPerm === null)        return false;
  301.         // Get Acl
  302.         $acl = $this->aclRepository->findOneBy(array(
  303.             'function'        =>    $function,
  304.             'permission'    =>    $aclPerm
  305.         ));
  306.         if ($acl === null)        return false;
  307.         // Since only one acl type can exist
  308.         // we can return the result of the acl_permission
  309.         return $acl->getValue();
  310.     }
  311.     // Plan.io Task #4507
  312.     /**
  313.      * Vendor invoices are now entered through the received invoices module, so this legacy
  314.      * creation path is closed for everyone whatever the ACL says. Existing vendor invoice
  315.      * costs stay viewable and editable through the regular cost attributes.
  316.      *
  317.      * Plan.io Task #4683
  318.      */
  319.     public function canAddVendorInvoice(Access $user, AccessFunction $function)
  320.     {
  321.         return false;
  322.     }
  323.     private function canList(Access $user, AccessFunction $function)
  324.     {
  325.         // Get Acl_Permission
  326.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  327.         if ($aclPerm === null)        return false;
  328.         // Get Acl
  329.         $acl = $this->aclRepository->findOneBy(array(
  330.             'function'        =>    $function,
  331.             'permission'    =>    $aclPerm
  332.         ));
  333.         if ($acl === null)        return false;
  334.         // Since only one acl type can exist
  335.         // we can return the result of the acl_permission
  336.         return $acl->getValue();
  337.     }
  338.     private function canListSociety(Access $user, AccessFunction $function)
  339.     {
  340.         // Get Acl_Permission
  341.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  342.         if ($aclPerm === null)        return false;
  343.         // Get Acl
  344.         $acl = $this->aclRepository->findOneBy(array(
  345.             'function'        =>    $function,
  346.             'permission'    =>    $aclPerm
  347.         ));
  348.         if ($acl === null)        return false;
  349.         // Since only one acl type can exist
  350.         // we can return the result of the acl_permission
  351.         // Further filtering is done in the Controller
  352.         return $acl->getValue();
  353.     }
  354.     private function canListOwn(Access $user, AccessFunction $function)
  355.     {
  356.         // Get Acl_Permission
  357.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_OWN);
  358.         if ($aclPerm === null)        return false;
  359.         // Get Acl
  360.         $acl = $this->aclRepository->findOneBy(array(
  361.             'function'        =>    $function,
  362.             'permission'    =>    $aclPerm
  363.         ));
  364.         if ($acl === null)        return false;
  365.         // Since only one acl type can exist
  366.         // we can return the result of the acl_permission
  367.         // Further filtering is done in the Controller
  368.         return $acl->getValue();
  369.     }
  370.     private function canListAny(Access $user, AccessFunction $function)
  371.     {
  372.         // Two Acl_Permission may exist
  373.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING);
  374.         $aclPermSociety = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_SOCIETY);
  375.         $aclPermOwn = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_LISTING_OWN);
  376.         // If all are null, exit
  377.         if ($aclPerm === null && $aclPermSociety === null && $aclPermOwn === null)
  378.             return false;
  379.         // Get First one
  380.         if ($aclPerm !== null)
  381.         {
  382.             $acl = $this->aclRepository->findOneBy(array(
  383.                 'function'        =>    $function,
  384.                 'permission'    =>    $aclPerm
  385.             ));
  386.             if ($acl !== null)
  387.             {
  388.                 if ($acl->getValue())
  389.                 {
  390.                     // A single positive answer is enough
  391.                     return true;
  392.                 }
  393.             }
  394.         }
  395.         // If we are here it means that nothing good has been found
  396.         // Load second permission
  397.         if ($aclPermSociety !== null)
  398.         {
  399.             $acl = $this->aclRepository->findOneBy(array(
  400.                 'function'        =>    $function,
  401.                 'permission'    =>    $aclPermSociety
  402.             ));
  403.             if ($acl !== null)
  404.             {
  405.                 if ($acl->getValue())
  406.                 {
  407.                     // A single positive answer is enough
  408.                     return true;
  409.                 }
  410.             }
  411.         }
  412.         // If we are here it means that nothing good has been found
  413.         // Load third permission
  414.         if ($aclPermOwn !== null)
  415.         {
  416.             $acl = $this->aclRepository->findOneBy(array(
  417.                 'function'        =>    $function,
  418.                 'permission'    =>    $aclPermOwn
  419.             ));
  420.             if ($acl !== null)
  421.             {
  422.                 if ($acl->getValue())
  423.                 {
  424.                     // A single positive answer is enough
  425.                     return true;
  426.                 }
  427.             }
  428.         }
  429.         // If we are here, all hope is lost
  430.         return false;
  431.     }
  432.     private function canView(Cost $cost, Access $user, AccessFunction $function)
  433.     {
  434.         // Get Acl_Permissions
  435.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW);
  436.         $aclPermSociety = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_SOCIETY);
  437.         $aclPermOwn = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_VIEW_OWN);
  438.         // If all are null, exit
  439.         if ($aclPerm === null && $aclPermSociety === null && $aclPermOwn === null)
  440.             return false;
  441.         // Get First one
  442.         if ($aclPerm !== null)
  443.         {
  444.             $acl = $this->aclRepository->findOneBy(array(
  445.                 'function'        =>    $function,
  446.                 'permission'    =>    $aclPerm
  447.             ));
  448.             if ($acl !== null)
  449.             {
  450.                 if ($acl->getValue())
  451.                 {
  452.                     // A single positive answer is enough
  453.                     return true;
  454.                 }
  455.             }
  456.         }
  457.         // If we are here it means that nothing good has been found
  458.         // Load second permission
  459.         if ($aclPermSociety !== null)
  460.         {
  461.             $acl = $this->aclRepository->findOneBy(array(
  462.                 'function'        =>    $function,
  463.                 'permission'    =>    $aclPermSociety
  464.             ));
  465.             if ($acl !== null)
  466.             {
  467.                 if ($acl->getValue())
  468.                 {
  469.                     // A single positive answer is enough
  470.                     // In this case the good answer will be provided by the checkSociety
  471.                     return $this->checkSociety($cost, $user);
  472.                 }
  473.             }
  474.         }
  475.         // If we are here it means that nothing good has been found
  476.         // Load third permission
  477.         if ($aclPermOwn !== null)
  478.         {
  479.             $acl = $this->aclRepository->findOneBy(array(
  480.                 'function'        =>    $function,
  481.                 'permission'    =>    $aclPermOwn
  482.             ));
  483.             if ($acl !== null)
  484.             {
  485.                 if ($acl->getValue())
  486.                 {
  487.                     // A single positive answer is enough
  488.                     // In this case the good answer will be provided by the checkOwn
  489.                     return $this->checkOwn($cost, $user);
  490.                 }
  491.             }
  492.         }
  493.         // If we are here, all hope is lost
  494.         return false;
  495.     }
  496.     private function canEdit(Cost $cost, Access $user, AccessFunction $function)
  497.     {
  498.         // Children only
  499.         // Plan.io Task #4416 => VendorInvoice also
  500.         if ($cost->getParent() === null && $cost->isNotVendorInvoice())
  501.         {
  502.             return false;
  503.         }
  504.         // If the initial status has changed => Deny editing
  505.         if ($cost->getStatus() === null)
  506.         {
  507.             // This should not happen
  508.             return false;
  509.         }
  510.         else
  511.         {
  512.             if ($cost->getStatus()->isNotDefaultValue())
  513.             {
  514.                 return false;
  515.             }
  516.         }
  517.         // Three Acl_Permission may exist
  518.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT);
  519.         $aclPermSociety = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_SOCIETY);
  520.         $aclPermOwn = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_OWN);
  521.         // If all are null, exit
  522.         if ($aclPerm === null && $aclPermSociety === null && $aclPermOwn === null)
  523.             return false;
  524.         // Get First one
  525.         if ($aclPerm !== null)
  526.         {
  527.             $acl = $this->aclRepository->findOneBy(array(
  528.                 'function'        =>    $function,
  529.                 'permission'    =>    $aclPerm
  530.             ));
  531.             if ($acl !== null)
  532.             {
  533.                 if ($acl->getValue())
  534.                 {
  535.                     // A single positive answer is enough
  536.                     return true;
  537.                 }
  538.             }
  539.         }
  540.         // If we are here it means that nothing good has been found
  541.         // Load second permission
  542.         if ($aclPermSociety !== null)
  543.         {
  544.             $acl = $this->aclRepository->findOneBy(array(
  545.                 'function'        =>    $function,
  546.                 'permission'    =>    $aclPermSociety
  547.             ));
  548.             if ($acl !== null)
  549.             {
  550.                 if ($acl->getValue())
  551.                 {
  552.                     // A single positive answer is enough
  553.                     // In this case the good answer will be provided by the checkSociety
  554.                     return $this->checkSociety($cost, $user);
  555.                 }
  556.             }
  557.         }
  558.         // If we are here it means that nothing good has been found
  559.         // Load third permission
  560.         if ($aclPermOwn !== null)
  561.         {
  562.             $acl = $this->aclRepository->findOneBy(array(
  563.                 'function'        =>    $function,
  564.                 'permission'    =>    $aclPermOwn
  565.             ));
  566.             if ($acl !== null)
  567.             {
  568.                 if ($acl->getValue())
  569.                 {
  570.                     // A single positive answer is enough
  571.                     // In this case the good answer will be provided by the checkOwn
  572.                     return $this->checkOwn($cost, $user);
  573.                 }
  574.             }
  575.         }
  576.         // If we are here, all hope is lost
  577.         return false;
  578.     }
  579.     private function canEditStatus(Cost $cost, Access $user, AccessFunction $function)
  580.     {
  581.         // Parent only
  582.         if (!$cost->isParent())
  583.         {
  584.             return false;
  585.         }
  586.         // Two Acl_Permission may exist
  587.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_STATUS);
  588.         $aclPermSociety = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_EDIT_STATUS_SOCIETY);
  589.         // If all are null, exit
  590.         if ($aclPerm === null && $aclPermSociety === null)
  591.             return false;
  592.         // Get First one
  593.         if ($aclPerm !== null)
  594.         {
  595.             $acl = $this->aclRepository->findOneBy(array(
  596.                 'function'        =>    $function,
  597.                 'permission'    =>    $aclPerm
  598.             ));
  599.             if ($acl !== null)
  600.             {
  601.                 if ($acl->getValue())
  602.                 {
  603.                     // A single positive answer is enough
  604.                     return true;
  605.                 }
  606.             }
  607.         }
  608.         // If we are here it means that nothing good has been found
  609.         // Load second permission
  610.         if ($aclPermSociety !== null)
  611.         {
  612.             $acl = $this->aclRepository->findOneBy(array(
  613.                 'function'        =>    $function,
  614.                 'permission'    =>    $aclPermSociety
  615.             ));
  616.             if ($acl !== null)
  617.             {
  618.                 if ($acl->getValue())
  619.                 {
  620.                     // A single positive answer is enough
  621.                     // In this case the good answer will be provided by the checkSociety
  622.                     return $this->checkSociety($cost, $user);
  623.                 }
  624.             }
  625.         }
  626.         // If we are here, all hope is lost
  627.         return false;
  628.     }
  629.     public function canEditType(Cost $cost, Access $user, AccessFunction $function)
  630.     {
  631.         // Parents only
  632.         if ($cost->getParent() !== null)
  633.         {
  634.             return false;
  635.         }
  636.         // No Acl_Permissions for now (Same as Rekto version)
  637.         if ($cost->getStatus() === null)
  638.         {
  639.             return false;
  640.         }
  641.         if ($cost->getStatus()->isDefaultValue())
  642.         {
  643.             return true;
  644.         }
  645.         // If we are here, all hope is lost
  646.         return false;
  647.     }
  648.     public function canDelete(Cost $cost, Access $user, AccessFunction $function)
  649.     {
  650.         // Children only
  651.         // Plan.io Task #4416 => VendorInvoice also
  652.         if ($cost->getParent() === null && $cost->isNotVendorInvoice())
  653.         {
  654.             return false;
  655.         }
  656.         // Check status (children only => avoid error when dealing with VendorInvoice Costs)
  657.         if ($cost->getParent() !== null)
  658.         {
  659.             if ($cost->getParent()->getStatus() === null)
  660.             {
  661.                 // This should not happen
  662.                 return false;
  663.             }
  664.             if ($cost->getParent()->getStatus()->deniesDelete())
  665.             {
  666.                 return false;
  667.             }
  668.         }
  669.         else
  670.         {
  671.             // Parent is null, so this is a Cost VendorInvoice
  672.             // => Check status directly
  673.             if ($cost->getStatus()->deniesDelete())
  674.             {
  675.                 return false;
  676.             }
  677.         }
  678.         // Three Acl_Permission may exist
  679.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE);
  680.         $aclPermSociety = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE_SOCIETY);
  681.         $aclPermOwn = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_DELETE_OWN);
  682.         // If all are null, exit
  683.         if ($aclPerm === null && $aclPermSociety === null && $aclPermOwn === null)
  684.             return false;
  685.         // Get First one
  686.         if ($aclPerm !== null)
  687.         {
  688.             $acl = $this->aclRepository->findOneBy(array(
  689.                 'function'        =>    $function,
  690.                 'permission'    =>    $aclPerm
  691.             ));
  692.             if ($acl !== null)
  693.             {
  694.                 if ($acl->getValue())
  695.                 {
  696.                     // A single positive answer is enough
  697.                     return true;
  698.                 }
  699.             }
  700.         }
  701.         // If we are here it means that nothing good has been found
  702.         // Load second permission
  703.         if ($aclPermSociety !== null)
  704.         {
  705.             $acl = $this->aclRepository->findOneBy(array(
  706.                 'function'        =>    $function,
  707.                 'permission'    =>    $aclPermSociety
  708.             ));
  709.             if ($acl !== null)
  710.             {
  711.                 if ($acl->getValue())
  712.                 {
  713.                     // A single positive answer is enough
  714.                     // In this case the good answer will be provided by the checkSociety
  715.                     return $this->checkSociety($cost, $user);
  716.                 }
  717.             }
  718.         }
  719.         // If we are here it means that nothing good has been found
  720.         // Load third permission
  721.         if ($aclPermOwn !== null)
  722.         {
  723.             $acl = $this->aclRepository->findOneBy(array(
  724.                 'function'        =>    $function,
  725.                 'permission'    =>    $aclPermOwn
  726.             ));
  727.             if ($acl !== null)
  728.             {
  729.                 if ($acl->getValue())
  730.                 {
  731.                     // A single positive answer is enough
  732.                     // In this case the good answer will be provided by the checkOwn
  733.                     return $this->checkOwn($cost, $user);
  734.                 }
  735.             }
  736.         }
  737.         // If we are here, all hope is lost
  738.         return false;
  739.     }
  740.     public function canMarkAsSeen(Cost $cost, Access $user, AccessFunction $function)
  741.     {
  742.         // Children only
  743.         if ($cost->getParent() === null)
  744.         {
  745.             return false;
  746.         }
  747.         // Get Acl_Permission
  748.         $aclPerm = $this->aclPermissionRepository->findOneByName(self::ACL_PERM_SEEN);
  749.         if ($aclPerm === null)        return false;
  750.         // Get Acl
  751.         $acl = $this->aclRepository->findOneBy(array(
  752.             'function'        =>    $function,
  753.             'permission'    =>    $aclPerm
  754.         ));
  755.         if ($acl === null)        return false;
  756.         // Since only one acl type can exist
  757.         // we can return the result of the acl_permission
  758.         return $acl->getValue();
  759.     }
  760.     public function canAddCostNote(Cost $cost, Access $user, AccessFunction $function)
  761.     {
  762.         // Only parent case
  763.         if ($cost->isChild())
  764.         {
  765.             return false;
  766.         }
  767.         // In all cases (Plan.io Task #3001)
  768.         return true;
  769.     }
  770.     public function canEditCostNote(CostNote $costNote, Access $user, AccessFunction $function)
  771.     {
  772.         if ($costNote->getCost() === null || $costNote->getAuthor() === null)
  773.         {
  774.             // Should never happen
  775.             return false;
  776.         }
  777.         // Author case
  778.         if ($costNote->getAuthor()->equals($user))
  779.         {
  780.             return true;
  781.         }
  782.         // In all cases (Plan.io Task #3001)
  783.         return true;
  784.     }
  785.     public function canDeleteCostNote(CostNote $costNote, Access $user, AccessFunction $function)
  786.     {
  787.         if ($costNote->getCost() === null || $costNote->getAuthor() === null)
  788.         {
  789.             // Should never happen
  790.             return false;
  791.         }
  792.         // Author case
  793.         if ($costNote->getAuthor()->equals($user))
  794.         {
  795.             return true;
  796.         }
  797.         // In all cases (Plan.io Task #3001)
  798.         return true;
  799.     }
  800. }