mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-25 14:42:48 +00:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			#361-impro
			...
			workflow/d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d4ce832e75 | |||
| 276b5ea394 | 
| @@ -12,6 +12,7 @@ declare(strict_types=1); | ||||
| namespace Chill\DocStoreBundle\Workflow; | ||||
|  | ||||
| use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument; | ||||
| use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter; | ||||
| use Chill\MainBundle\Entity\Workflow\EntityWorkflow; | ||||
| use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface; | ||||
| use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; | ||||
| @@ -36,6 +37,13 @@ class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowHandler | ||||
|         $this->translator = $translator; | ||||
|     } | ||||
|  | ||||
|     public function getDeletionRoles(): array | ||||
|     { | ||||
|         return [ | ||||
|             AccompanyingCourseDocumentVoter::DELETE, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function getEntityData(EntityWorkflow $entityWorkflow, array $options = []): array | ||||
|     { | ||||
|         $course = $this->getRelatedEntity($entityWorkflow) | ||||
| @@ -66,6 +74,18 @@ class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowHandler | ||||
|         return $this->repository->find($entityWorkflow->getRelatedEntityId()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param AccompanyingCourseDocument $object | ||||
|      * | ||||
|      * @return array[] | ||||
|      */ | ||||
|     public function getRelatedObjects(object $object): array | ||||
|     { | ||||
|         return [ | ||||
|             ['entityClass' => AccompanyingCourseDocument::class, 'entityId' => $object->getId()], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function getRoleShow(EntityWorkflow $entityWorkflow): ?string | ||||
|     { | ||||
|         return null; | ||||
| @@ -84,6 +104,11 @@ class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowHandler | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function isObjectSupported(object $object): bool | ||||
|     { | ||||
|         return $object instanceof AccompanyingCourseDocument; | ||||
|     } | ||||
|  | ||||
|     public function supports(EntityWorkflow $entityWorkflow, array $options = []): bool | ||||
|     { | ||||
|         return $entityWorkflow->getRelatedEntityClass() === AccompanyingCourseDocument::class; | ||||
|   | ||||
| @@ -256,6 +256,13 @@ class ChillMainExtension extends Extension implements | ||||
|             'channels' => ['chill'], | ||||
|         ]); | ||||
|  | ||||
|         $container->prependExtensionConfig('security', [ | ||||
|             'access_decision_manager' => [ | ||||
|                 'strategy' => 'unanimous', | ||||
|                 'allow_if_all_abstain' => false, | ||||
|             ], | ||||
|         ]); | ||||
|  | ||||
|         //add crud api | ||||
|         $this->prependCruds($container); | ||||
|     } | ||||
|   | ||||
| @@ -55,6 +55,30 @@ class EntityWorkflowRepository implements ObjectRepository | ||||
|         return (int) $qb->getQuery()->getSingleScalarResult(); | ||||
|     } | ||||
|  | ||||
|     public function countRelatedWorkflows(array $relateds): int | ||||
|     { | ||||
|         $qb = $this->repository->createQueryBuilder('w'); | ||||
|  | ||||
|         $orX = $qb->expr()->orX(); | ||||
|         $i = 0; | ||||
|  | ||||
|         foreach ($relateds as $related) { | ||||
|             $orX->add( | ||||
|                 $qb->expr()->andX( | ||||
|                     $qb->expr()->eq('w.relatedEntityClass', ':entity_class_' . $i), | ||||
|                     $qb->expr()->eq('w.relatedEntityId', ':entity_id_' . $i) | ||||
|                 ) | ||||
|             ); | ||||
|             $qb | ||||
|                 ->setParameter('entity_class_' . $i, $related['entityClass']) | ||||
|                 ->setParameter('entity_id_' . $i, $related['entityId']); | ||||
|             ++$i; | ||||
|         } | ||||
|         $qb->where($orX); | ||||
|  | ||||
|         return $qb->select('COUNT(w)')->getQuery()->getSingleScalarResult(); | ||||
|     } | ||||
|  | ||||
|     public function find($id): ?EntityWorkflow | ||||
|     { | ||||
|         return $this->repository->find($id); | ||||
|   | ||||
| @@ -0,0 +1,65 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Chill\MainBundle\Security\Authorization; | ||||
|  | ||||
| use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository; | ||||
| use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface; | ||||
| use RuntimeException; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||||
| use Symfony\Component\Security\Core\Authorization\Voter\Voter; | ||||
| use function in_array; | ||||
| use function is_object; | ||||
|  | ||||
| class WorkflowEntityDeletionVoter extends Voter | ||||
| { | ||||
|     private EntityWorkflowRepository $entityWorkflowRepository; | ||||
|  | ||||
|     /** | ||||
|      * @var iterable|EntityWorkflowHandlerInterface[] | ||||
|      */ | ||||
|     private iterable $handlers; | ||||
|  | ||||
|     public function __construct($handlers, EntityWorkflowRepository $entityWorkflowRepository) | ||||
|     { | ||||
|         $this->handlers = $handlers; | ||||
|         $this->entityWorkflowRepository = $entityWorkflowRepository; | ||||
|     } | ||||
|  | ||||
|     protected function supports($attribute, $subject) | ||||
|     { | ||||
|         if (!is_object($subject)) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         foreach ($this->handlers as $handler) { | ||||
|             if ($handler->isObjectSupported($subject) | ||||
|                 && in_array($attribute, $handler->getDeletionRoles($subject), true)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     protected function voteOnAttribute($attribute, $subject, TokenInterface $token) | ||||
|     { | ||||
|         foreach ($this->handlers as $handler) { | ||||
|             if ($handler->isObjectSupported($subject)) { | ||||
|                 return 0 === $this->entityWorkflowRepository->countRelatedWorkflows( | ||||
|                     $handler->getRelatedObjects($subject) | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         throw new RuntimeException('no handlers found'); | ||||
|     } | ||||
| } | ||||
| @@ -15,12 +15,19 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflow; | ||||
|  | ||||
| interface EntityWorkflowHandlerInterface | ||||
| { | ||||
|     /** | ||||
|      * @return array|string[] | ||||
|      */ | ||||
|     public function getDeletionRoles(): array; | ||||
|  | ||||
|     public function getEntityData(EntityWorkflow $entityWorkflow, array $options = []): array; | ||||
|  | ||||
|     public function getEntityTitle(EntityWorkflow $entityWorkflow, array $options = []): string; | ||||
|  | ||||
|     public function getRelatedEntity(EntityWorkflow $entityWorkflow): ?object; | ||||
|  | ||||
|     public function getRelatedObjects(object $object): array; | ||||
|  | ||||
|     /** | ||||
|      * Return a string representing the role required for seeing the workflow. | ||||
|      * | ||||
| @@ -33,6 +40,8 @@ interface EntityWorkflowHandlerInterface | ||||
|  | ||||
|     public function getTemplateData(EntityWorkflow $entityWorkflow, array $options = []): array; | ||||
|  | ||||
|     public function isObjectSupported(object $object): bool; | ||||
|  | ||||
|     public function supports(EntityWorkflow $entityWorkflow, array $options = []): bool; | ||||
|  | ||||
|     public function supportsFreeze(EntityWorkflow $entityWorkflow, array $options = []): bool; | ||||
|   | ||||
| @@ -75,3 +75,9 @@ services: | ||||
|             $locker: '@Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker' | ||||
|         tags: | ||||
|             - { name: security.voter } | ||||
|  | ||||
|     Chill\MainBundle\Security\Authorization\WorkflowEntityDeletionVoter: | ||||
|         autoconfigure: true | ||||
|         autowire: true | ||||
|         arguments: | ||||
|             $handlers: !tagged_iterator chill_main.workflow_handler | ||||
|   | ||||
| @@ -26,7 +26,7 @@ | ||||
|              ></list-workflow-modal> | ||||
|  | ||||
|            </li> | ||||
|             <li> | ||||
|             <li v-if="canDelete"> | ||||
|                <a class="btn btn-delete" @click="modal.showModal = true" :title="$t('action.delete')"></a> | ||||
|             </li> | ||||
|          </ul> | ||||
| @@ -98,6 +98,19 @@ export default { | ||||
|       pickedEvaluations() { | ||||
|          return this.$store.state.evaluationsPicked; | ||||
|       }, | ||||
|       canDelete() { | ||||
|         if (this.evaluation.workflows.length > 0) { | ||||
|           return false; | ||||
|         } | ||||
|  | ||||
|          for (let doc of this.evaluation.documents) { | ||||
|            if (doc.workflows.length > 0) { | ||||
|              return false; | ||||
|            } | ||||
|          } | ||||
|  | ||||
|          return true; | ||||
|       }, | ||||
|    }, | ||||
|    methods: { | ||||
|       removeEvaluation(e) { | ||||
|   | ||||
| @@ -101,7 +101,7 @@ | ||||
|                    <li> | ||||
|                      <a :href="buildEditLink(d.storedObject)" class="btn btn-wopilink"></a> | ||||
|                    </li> | ||||
|                    <li> | ||||
|                    <li v-if="d.workflows.length === 0"> | ||||
|                      <a class="btn btn-delete" @click="removeDocument(d)"> | ||||
|                      </a> | ||||
|                    </li> | ||||
|   | ||||
| @@ -130,11 +130,13 @@ | ||||
|                    href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_edit', { 'id': w.id }) }}" | ||||
|                 ></a> | ||||
|             </li> | ||||
|             <li> | ||||
|                 <a class="btn btn-delete" title="{{ 'Delete'|trans }}" | ||||
|                    href="{{ path('chill_person_accompanying_period_work_delete', { 'id': w.id } ) }}" | ||||
|                 ></a> | ||||
|             </li> | ||||
|             {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_DELETE', w) %} | ||||
|                 <li> | ||||
|                     <a class="btn btn-delete" title="{{ 'Delete'|trans }}" | ||||
|                        href="{{ path('chill_person_accompanying_period_work_delete', { 'id': w.id } ) }}" | ||||
|                     ></a> | ||||
|                 </li> | ||||
|             {% endif %} | ||||
|         </ul> | ||||
|         {% endif %} | ||||
|     </div> | ||||
|   | ||||
| @@ -24,6 +24,8 @@ class AccompanyingPeriodWorkVoter extends Voter | ||||
| { | ||||
|     public const CREATE = 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_CREATE'; | ||||
|  | ||||
|     public const DELETE = 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_DELETE'; | ||||
|  | ||||
|     public const SEE = 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_SEE'; | ||||
|  | ||||
|     public const UPDATE = 'CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE'; | ||||
| @@ -60,6 +62,7 @@ class AccompanyingPeriodWorkVoter extends Voter | ||||
|  | ||||
|                 case self::CREATE: | ||||
|                 case self::UPDATE: | ||||
|                 case self::DELETE: | ||||
|                     return $this->security->isGranted(AccompanyingPeriodVoter::EDIT, $subject->getAccompanyingPeriod()); | ||||
|  | ||||
|                 default: | ||||
| @@ -86,6 +89,6 @@ class AccompanyingPeriodWorkVoter extends Voter | ||||
|  | ||||
|     private function getRoles(): array | ||||
|     { | ||||
|         return [self::SEE, self::CREATE, self::UPDATE]; | ||||
|         return [self::SEE, self::CREATE, self::UPDATE, self::DELETE]; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -37,6 +37,13 @@ class AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler implements EntityW | ||||
|         $this->translator = $translator; | ||||
|     } | ||||
|  | ||||
|     public function getDeletionRoles(): array | ||||
|     { | ||||
|         return [ | ||||
|             '_', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function getEntityData(EntityWorkflow $entityWorkflow, array $options = []): array | ||||
|     { | ||||
|         $doc = $this->getRelatedEntity($entityWorkflow); | ||||
| @@ -63,6 +70,18 @@ class AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler implements EntityW | ||||
|         return $this->repository->find($entityWorkflow->getRelatedEntityId()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param AccompanyingPeriodWorkEvaluationDocument $object | ||||
|      * | ||||
|      * @return array[] | ||||
|      */ | ||||
|     public function getRelatedObjects(object $object): array | ||||
|     { | ||||
|         return [ | ||||
|             ['entityClass' => AccompanyingPeriodWorkEvaluationDocument::class, $object->getId()], | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function getRoleShow(EntityWorkflow $entityWorkflow): ?string | ||||
|     { | ||||
|         return AccompanyingPeriodWorkEvaluationDocumentVoter::SEE; | ||||
| @@ -84,6 +103,11 @@ class AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler implements EntityW | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function isObjectSupported(object $object): bool | ||||
|     { | ||||
|         return $object instanceof AccompanyingPeriodWorkEvaluationDocument; | ||||
|     } | ||||
|  | ||||
|     public function supports(EntityWorkflow $entityWorkflow, array $options = []): bool | ||||
|     { | ||||
|         return $entityWorkflow->getRelatedEntityClass() === AccompanyingPeriodWorkEvaluationDocument::class; | ||||
|   | ||||
| @@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflow; | ||||
| use Chill\MainBundle\Templating\TranslatableStringHelperInterface; | ||||
| use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface; | ||||
| use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; | ||||
| use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument; | ||||
| use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationRepository; | ||||
| use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkEvaluationVoter; | ||||
| use Symfony\Contracts\Translation\TranslatorInterface; | ||||
| @@ -37,6 +38,11 @@ class AccompanyingPeriodWorkEvaluationWorkflowHandler implements EntityWorkflowH | ||||
|         $this->translator = $translator; | ||||
|     } | ||||
|  | ||||
|     public function getDeletionRoles(): array | ||||
|     { | ||||
|         return ['_']; | ||||
|     } | ||||
|  | ||||
|     public function getEntityData(EntityWorkflow $entityWorkflow, array $options = []): array | ||||
|     { | ||||
|         $evaluation = $this->getRelatedEntity($entityWorkflow); | ||||
| @@ -61,6 +67,20 @@ class AccompanyingPeriodWorkEvaluationWorkflowHandler implements EntityWorkflowH | ||||
|         return $this->repository->find($entityWorkflow->getRelatedEntityId()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param AccompanyingPeriodWorkEvaluation $object | ||||
|      */ | ||||
|     public function getRelatedObjects(object $object): array | ||||
|     { | ||||
|         $relateds[] = ['entityClass' => AccompanyingPeriodWorkEvaluation::class, 'entityId' => $object->getId()]; | ||||
|  | ||||
|         foreach ($object->getDocuments() as $doc) { | ||||
|             $relateds[] = ['entityClass' => AccompanyingPeriodWorkEvaluationDocument::class, 'entityId' => $doc->getId()]; | ||||
|         } | ||||
|  | ||||
|         return $relateds; | ||||
|     } | ||||
|  | ||||
|     public function getRoleShow(EntityWorkflow $entityWorkflow): ?string | ||||
|     { | ||||
|         return AccompanyingPeriodWorkEvaluationVoter::SEE; | ||||
| @@ -79,6 +99,11 @@ class AccompanyingPeriodWorkEvaluationWorkflowHandler implements EntityWorkflowH | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function isObjectSupported(object $object): bool | ||||
|     { | ||||
|         return $object instanceof AccompanyingPeriodWorkEvaluation; | ||||
|     } | ||||
|  | ||||
|     public function supports(EntityWorkflow $entityWorkflow, array $options = []): bool | ||||
|     { | ||||
|         return $entityWorkflow->getRelatedEntityClass() === AccompanyingPeriodWorkEvaluation::class; | ||||
|   | ||||
| @@ -15,7 +15,10 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflow; | ||||
| use Chill\MainBundle\Templating\TranslatableStringHelperInterface; | ||||
| use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface; | ||||
| use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; | ||||
| use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation; | ||||
| use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument; | ||||
| use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository; | ||||
| use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkVoter; | ||||
| use Symfony\Contracts\Translation\TranslatorInterface; | ||||
|  | ||||
| class AccompanyingPeriodWorkWorkflowHandler implements EntityWorkflowHandlerInterface | ||||
| @@ -36,6 +39,11 @@ class AccompanyingPeriodWorkWorkflowHandler implements EntityWorkflowHandlerInte | ||||
|         $this->translator = $translator; | ||||
|     } | ||||
|  | ||||
|     public function getDeletionRoles(): array | ||||
|     { | ||||
|         return [AccompanyingPeriodWorkVoter::DELETE]; | ||||
|     } | ||||
|  | ||||
|     public function getEntityData(EntityWorkflow $entityWorkflow, array $options = []): array | ||||
|     { | ||||
|         return [ | ||||
| @@ -58,6 +66,24 @@ class AccompanyingPeriodWorkWorkflowHandler implements EntityWorkflowHandlerInte | ||||
|         return $this->repository->find($entityWorkflow->getRelatedEntityId()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param AccompanyingPeriodWork $object | ||||
|      */ | ||||
|     public function getRelatedObjects(object $object): array | ||||
|     { | ||||
|         $relateds[] = ['entityClass' => AccompanyingPeriodWork::class, 'entityId' => $object->getId()]; | ||||
|  | ||||
|         foreach ($object->getAccompanyingPeriodWorkEvaluations() as $evaluation) { | ||||
|             $relateds[] = ['entityClass' => AccompanyingPeriodWorkEvaluation::class, 'entityId' => $evaluation->getId()]; | ||||
|  | ||||
|             foreach ($evaluation->getDocuments() as $doc) { | ||||
|                 $relateds[] = ['entityClass' => AccompanyingPeriodWorkEvaluationDocument::class, 'entityId' => $doc->getId()]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $relateds; | ||||
|     } | ||||
|  | ||||
|     public function getRoleShow(EntityWorkflow $entityWorkflow): ?string | ||||
|     { | ||||
|         return null; | ||||
| @@ -76,6 +102,11 @@ class AccompanyingPeriodWorkWorkflowHandler implements EntityWorkflowHandlerInte | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function isObjectSupported(object $object): bool | ||||
|     { | ||||
|         return $object instanceof AccompanyingPeriodWork; | ||||
|     } | ||||
|  | ||||
|     public function supports(EntityWorkflow $entityWorkflow, array $options = []): bool | ||||
|     { | ||||
|         return $entityWorkflow->getRelatedEntityClass() === AccompanyingPeriodWork::class; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user