mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 09:18:24 +00:00 
			
		
		
		
	Compare commits
	
		
			10 Commits
		
	
	
		
			v3.0.0-RC9
			...
			issue706_c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b59c69bce4 | ||
|  | 6f9da67942 | ||
|  | 609e2e1610 | ||
|  | d940d13d7d | ||
|  | 1cf99b4383 | ||
|  | c969b35fd1 | ||
|  | cbf8a9ff71 | ||
|  | 7c18899249 | ||
|  | f4f465b33a | ||
|  | aed7fcebae | 
| @@ -14,6 +14,7 @@ namespace Chill\MainBundle\Controller; | ||||
| use Chill\MainBundle\Entity\Notification; | ||||
| use Chill\MainBundle\Entity\NotificationComment; | ||||
| use Chill\MainBundle\Entity\User; | ||||
| use Chill\MainBundle\Entity\Workflow\EntityWorkflow; | ||||
| use Chill\MainBundle\Form\NotificationCommentType; | ||||
| use Chill\MainBundle\Form\NotificationType; | ||||
| use Chill\MainBundle\Notification\Exception\NotificationHandlerNotFound; | ||||
| @@ -21,6 +22,7 @@ use Chill\MainBundle\Notification\NotificationHandlerManager; | ||||
| use Chill\MainBundle\Pagination\PaginatorFactory; | ||||
| use Chill\MainBundle\Repository\NotificationRepository; | ||||
| use Chill\MainBundle\Repository\UserRepository; | ||||
| use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository; | ||||
| use Chill\MainBundle\Security\Authorization\NotificationVoter; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
| use Psr\Log\LoggerInterface; | ||||
| @@ -68,7 +70,8 @@ class NotificationController extends AbstractController | ||||
|         NotificationHandlerManager $notificationHandlerManager, | ||||
|         PaginatorFactory $paginatorFactory, | ||||
|         TranslatorInterface $translator, | ||||
|         UserRepository $userRepository | ||||
|         UserRepository $userRepository, | ||||
|         EntityWorkflowRepository $entityWorkflowRepository | ||||
|     ) { | ||||
|         $this->em = $em; | ||||
|         $this->logger = $logger; | ||||
| @@ -79,6 +82,7 @@ class NotificationController extends AbstractController | ||||
|         $this->paginatorFactory = $paginatorFactory; | ||||
|         $this->translator = $translator; | ||||
|         $this->userRepository = $userRepository; | ||||
|         $this->entityWorkflowRepository = $entityWorkflowRepository; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -345,6 +349,7 @@ class NotificationController extends AbstractController | ||||
|             'appendCommentForm' => isset($appendCommentForm) ? $appendCommentForm->createView() : null, | ||||
|             'editedCommentForm' => isset($editedCommentForm) ? $editedCommentForm->createView() : null, | ||||
|             'editedCommentId' => $commentId ?? null, | ||||
|             'notificationCc' => $this->isNotificationCc($notification), | ||||
|         ]); | ||||
|  | ||||
|         // we mark the notification as read after having computed the response | ||||
| @@ -364,6 +369,21 @@ class NotificationController extends AbstractController | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     private function isNotificationCc(Notification $notification): bool | ||||
|     { | ||||
|         $notificationCc = false; | ||||
|  | ||||
|         if ($notification->getRelatedEntityClass() === EntityWorkflow::class) { | ||||
|             $relatedEntity = $this->entityWorkflowRepository->findOneBy(['id' => $notification->getRelatedEntityId()]); | ||||
|  | ||||
|             if ($relatedEntity->getCurrentStepCreatedBy() !== $this->security->getUser()) { | ||||
|                 $notificationCc = true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $notificationCc; | ||||
|     } | ||||
|  | ||||
|     private function itemsForTemplate(array $notifications): array | ||||
|     { | ||||
|         $templateData = []; | ||||
| @@ -373,6 +393,7 @@ class NotificationController extends AbstractController | ||||
|                 'template' => $this->notificationHandlerManager->getTemplate($notification), | ||||
|                 'template_data' => $this->notificationHandlerManager->getTemplateData($notification), | ||||
|                 'notification' => $notification, | ||||
|                 'isNotificationCc' => $this->isNotificationCc($notification), | ||||
|             ]; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -93,6 +93,45 @@ class WorkflowApiController | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return a list of workflow which are waiting an action for the user. | ||||
|      * | ||||
|      * @Route("/api/1.0/main/workflow/my-cc", methods={"GET"}) | ||||
|      */ | ||||
|     public function myWorkflowCc(Request $request): JsonResponse | ||||
|     { | ||||
|         if (!$this->security->isGranted('ROLE_USER') || !$this->security->getUser() instanceof User) { | ||||
|             throw new AccessDeniedException(); | ||||
|         } | ||||
|  | ||||
|         $total = $this->entityWorkflowRepository->countByCc($this->security->getUser()); | ||||
|  | ||||
|         if ($request->query->getBoolean('countOnly', false)) { | ||||
|             return new JsonResponse( | ||||
|                 $this->serializer->serialize(new Counter($total), 'json'), | ||||
|                 JsonResponse::HTTP_OK, | ||||
|                 [], | ||||
|                 true | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $paginator = $this->paginatorFactory->create($total); | ||||
|  | ||||
|         $workflows = $this->entityWorkflowRepository->findByCc( | ||||
|             $this->security->getUser(), | ||||
|             ['id' => 'DESC'], | ||||
|             $paginator->getItemsPerPage(), | ||||
|             $paginator->getCurrentPageFirstItemNumber() | ||||
|         ); | ||||
|  | ||||
|         return new JsonResponse( | ||||
|             $this->serializer->serialize(new Collection($workflows, $paginator), 'json', ['groups' => ['read']]), | ||||
|             JsonResponse::HTTP_OK, | ||||
|             [], | ||||
|             true | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/api/1.0/main/workflow/{id}/subscribe", methods={"POST"}) | ||||
|      */ | ||||
|   | ||||
| @@ -224,6 +224,33 @@ class WorkflowController extends AbstractController | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/{_locale}/main/workflow/list/cc", name="chill_main_workflow_list_cc") | ||||
|      */ | ||||
|     public function myWorkflowsCc(Request $request): Response | ||||
|     { | ||||
|         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED'); | ||||
|  | ||||
|         $total = $this->entityWorkflowRepository->countByDest($this->getUser()); | ||||
|         $paginator = $this->paginatorFactory->create($total); | ||||
|  | ||||
|         $workflows = $this->entityWorkflowRepository->findByCc( | ||||
|             $this->getUser(), | ||||
|             ['createdAt' => 'DESC'], | ||||
|             $paginator->getItemsPerPage(), | ||||
|             $paginator->getCurrentPageFirstItemNumber() | ||||
|         ); | ||||
|  | ||||
|         return $this->render( | ||||
|             '@ChillMain/Workflow/list.html.twig', | ||||
|             [ | ||||
|                 'workflows' => $this->buildHandler($workflows), | ||||
|                 'paginator' => $paginator, | ||||
|                 'step' => 'cc', | ||||
|             ] | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/{_locale}/main/workflow/list/dest", name="chill_main_workflow_list_dest") | ||||
|      */ | ||||
| @@ -318,6 +345,7 @@ class WorkflowController extends AbstractController | ||||
|                 } | ||||
|  | ||||
|                 // TODO symfony 5: add those "future" on context ($workflow->apply($entityWorkflow, $transition, $context) | ||||
|                 $entityWorkflow->futureCcUsers = $transitionForm['future_cc_users']->getData(); | ||||
|                 $entityWorkflow->futureDestUsers = $transitionForm['future_dest_users']->getData(); | ||||
|                 $entityWorkflow->futureDestEmails = $transitionForm['future_dest_emails']->getData(); | ||||
|  | ||||
|   | ||||
| @@ -41,6 +41,13 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface | ||||
|  | ||||
|     use TrackUpdateTrait; | ||||
|  | ||||
|     /** | ||||
|      * a list of future cc users for the next steps. | ||||
|      * | ||||
|      * @var array|User[] | ||||
|      */ | ||||
|     public array $futureCcUsers = []; | ||||
|  | ||||
|     /** | ||||
|      * a list of future dest emails for the next steps. | ||||
|      * | ||||
|   | ||||
| @@ -32,6 +32,12 @@ class EntityWorkflowStep | ||||
|      */ | ||||
|     private string $accessKey; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\ManyToMany(targetEntity=User::class) | ||||
|      * @ORM\JoinTable(name="chill_main_workflow_entity_step_cc_user") | ||||
|      */ | ||||
|     private Collection $ccUser; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Column(type="text", options={"default": ""}) | ||||
|      */ | ||||
| @@ -114,11 +120,21 @@ class EntityWorkflowStep | ||||
|  | ||||
|     public function __construct() | ||||
|     { | ||||
|         $this->ccUser = new ArrayCollection(); | ||||
|         $this->destUser = new ArrayCollection(); | ||||
|         $this->destUserByAccessKey = new ArrayCollection(); | ||||
|         $this->accessKey = bin2hex(openssl_random_pseudo_bytes(32)); | ||||
|     } | ||||
|  | ||||
|     public function addCcUser(User $user): self | ||||
|     { | ||||
|         if (!$this->ccUser->contains($user)) { | ||||
|             $this->ccUser[] = $user; | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     public function addDestEmail(string $email): self | ||||
|     { | ||||
|         if (!in_array($email, $this->destEmail, true)) { | ||||
| @@ -167,6 +183,11 @@ class EntityWorkflowStep | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public function getCcUser(): Collection | ||||
|     { | ||||
|         return $this->ccUser; | ||||
|     } | ||||
|  | ||||
|     public function getComment(): string | ||||
|     { | ||||
|         return $this->comment; | ||||
| @@ -261,6 +282,13 @@ class EntityWorkflowStep | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public function removeCcUser(User $user): self | ||||
|     { | ||||
|         $this->ccUser->removeElement($user); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     public function removeDestEmail(string $email): self | ||||
|     { | ||||
|         $this->destEmail = array_filter($this->destEmail, static function (string $existing) use ($email) { | ||||
|   | ||||
| @@ -155,6 +155,12 @@ class WorkflowStepType extends AbstractType | ||||
|                     'multiple' => true, | ||||
|                     'mapped' => false, | ||||
|                 ]) | ||||
|                 ->add('future_cc_users', PickUserDynamicType::class, [ | ||||
|                     'label' => 'workflow.cc for next steps', | ||||
|                     'multiple' => true, | ||||
|                     'mapped' => false, | ||||
|                     'required' => false, | ||||
|                 ]) | ||||
|                 ->add('future_dest_emails', ChillCollectionType::class, [ | ||||
|                     'label' => 'workflow.dest by email', | ||||
|                     'help' => 'workflow.dest by email help', | ||||
|   | ||||
| @@ -74,7 +74,9 @@ class NotificationTwigExtensionRuntime implements RuntimeExtensionInterface | ||||
|         } | ||||
|  | ||||
|         return $environment->render('@ChillMain/Notification/extension_list_notifications_for.html.twig', [ | ||||
|             'notifications' => $notifications, 'appendCommentForms' => $appendCommentForms, | ||||
|             'notifications' => $notifications, | ||||
|             'appendCommentForms' => $appendCommentForms, | ||||
|             'notificationCc' => false, | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -27,6 +27,13 @@ class EntityWorkflowRepository implements ObjectRepository | ||||
|         $this->repository = $entityManager->getRepository(EntityWorkflow::class); | ||||
|     } | ||||
|  | ||||
|     public function countByCc(User $user): int | ||||
|     { | ||||
|         $qb = $this->buildQueryByCc($user)->select('count(ew)'); | ||||
|  | ||||
|         return (int) $qb->getQuery()->getSingleScalarResult(); | ||||
|     } | ||||
|  | ||||
|     public function countByDest(User $user): int | ||||
|     { | ||||
|         $qb = $this->buildQueryByDest($user)->select('count(ew)'); | ||||
| @@ -103,6 +110,19 @@ class EntityWorkflowRepository implements ObjectRepository | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|  | ||||
|     public function findByCc(User $user, ?array $orderBy = null, $limit = null, $offset = null): array | ||||
|     { | ||||
|         $qb = $this->buildQueryByCc($user)->select('ew'); | ||||
|  | ||||
|         foreach ($orderBy as $key => $sort) { | ||||
|             $qb->addOrderBy('ew.' . $key, $sort); | ||||
|         } | ||||
|  | ||||
|         $qb->setMaxResults($limit)->setFirstResult($offset); | ||||
|  | ||||
|         return $qb->getQuery()->getResult(); | ||||
|     } | ||||
|  | ||||
|     public function findByDest(User $user, ?array $orderBy = null, $limit = null, $offset = null): array | ||||
|     { | ||||
|         $qb = $this->buildQueryByDest($user)->select('ew'); | ||||
| @@ -165,6 +185,25 @@ class EntityWorkflowRepository implements ObjectRepository | ||||
|         return EntityWorkflow::class; | ||||
|     } | ||||
|  | ||||
|     private function buildQueryByCc(User $user): QueryBuilder | ||||
|     { | ||||
|         $qb = $this->repository->createQueryBuilder('ew'); | ||||
|  | ||||
|         $qb->join('ew.steps', 'step'); | ||||
|  | ||||
|         $qb->where( | ||||
|             $qb->expr()->andX( | ||||
|                 $qb->expr()->isMemberOf(':user', 'step.ccUser'), | ||||
|                 $qb->expr()->isNull('step.transitionAfter'), | ||||
|                 $qb->expr()->eq('step.isFinal', "'FALSE'") | ||||
|             ) | ||||
|         ); | ||||
|  | ||||
|         $qb->setParameter('user', $user); | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|  | ||||
|     private function buildQueryByDest(User $user): QueryBuilder | ||||
|     { | ||||
|         $qb = $this->repository->createQueryBuilder('ew'); | ||||
|   | ||||
| @@ -1,88 +1,25 @@ | ||||
| <template> | ||||
|     <div class="alert alert-light">{{ $t('my_workflows.description') }}</div> | ||||
|     <my-workflows-table :workflows="workflows" /> | ||||
|  | ||||
| <div class="alert alert-light">{{ $t('my_workflows.description') }}</div> | ||||
| <span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span> | ||||
| <tab-table v-else> | ||||
|     <template v-slot:thead> | ||||
|         <th scope="col">{{ $t('Object_workflow') }}</th> | ||||
|         <th scope="col">{{ $t('Step') }}</th> | ||||
|         <th scope="col">{{ $t('concerned_users') }}</th> | ||||
|         <th scope="col"></th> | ||||
|     </template> | ||||
|     <template v-slot:tbody> | ||||
|         <tr v-for="(w, i) in workflows.results" :key="`workflow-${i}`"> | ||||
|             <td>{{ w.title }}</td> | ||||
|             <td> | ||||
|                 <div class="workflow"> | ||||
|                     <div class="breadcrumb"> | ||||
|                         <i class="fa fa-circle me-1 text-chill-yellow mx-2"></i> | ||||
|                         <span class="mx-2">{{ getStep(w) }}</span> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </td> | ||||
|             <td v-if="w.datas.persons !== null"> | ||||
|                 <span v-for="p in w.datas.persons" class="me-1" :key="p.id"> | ||||
|                     <on-the-fly | ||||
|                         :type="p.type" | ||||
|                         :id="p.id" | ||||
|                         :buttonText="p.textAge" | ||||
|                         :displayBadge="'true' === 'true'" | ||||
|                         action="show"> | ||||
|                     </on-the-fly> | ||||
|                 </span> | ||||
|             </td> | ||||
|             <td> | ||||
|             <a class="btn btn-sm btn-show" :href="getUrl(w)"> | ||||
|                 {{ $t('show_entity', { entity: $t('the_workflow') }) }} | ||||
|             </a> | ||||
|             </td> | ||||
|         </tr> | ||||
|     </template> | ||||
| </tab-table> | ||||
|  | ||||
|     <div class="alert alert-light">{{ $t('my_workflows.description_cc') }}</div> | ||||
|     <my-workflows-table :workflows="workflowsCc" /> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapState, mapGetters } from "vuex"; | ||||
| import TabTable from "./TabTable"; | ||||
| import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly'; | ||||
| import { mapState } from "vuex"; | ||||
| import MyWorkflowsTable from './MyWorkflowsTable.vue'; | ||||
|  | ||||
| export default { | ||||
|     name: "MyWorkflows", | ||||
|     components: { | ||||
|         TabTable, | ||||
|         OnTheFly | ||||
|         MyWorkflowsTable | ||||
|     }, | ||||
|     computed: { | ||||
|         ...mapState([ | ||||
|             'workflows', | ||||
|             'workflowsCc', | ||||
|         ]), | ||||
|         ...mapGetters([ | ||||
|             'isWorkflowsLoaded', | ||||
|         ]), | ||||
|         noResults() { | ||||
|             if (!this.isWorkflowsLoaded) { | ||||
|                 return false; | ||||
|             } else { | ||||
|                 return this.workflows.count === 0; | ||||
|             } | ||||
|         }, | ||||
|     }, | ||||
|     methods: { | ||||
|         getUrl(w) { | ||||
|             return `/fr/main/workflow/${w.id}/show`; | ||||
|         }, | ||||
|         getStep(w) { | ||||
|             const lastStep = w.steps.length - 1 | ||||
|             return w.steps[lastStep].currentStep.text; | ||||
|         } | ||||
|     }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| span.outdated { | ||||
|     font-weight: bold; | ||||
|     color: var(--bs-warning); | ||||
| } | ||||
| </style> | ||||
| </script> | ||||
| @@ -0,0 +1,83 @@ | ||||
| <template> | ||||
|     <span v-if="hasNoResults(workflows)" class="chill-no-data-statement">{{ $t('no_data') }}</span> | ||||
|     <tab-table v-else> | ||||
|         <template v-slot:thead> | ||||
|             <th scope="col">{{ $t('Object_workflow') }}</th> | ||||
|             <th scope="col">{{ $t('Step') }}</th> | ||||
|             <th scope="col">{{ $t('concerned_users') }}</th> | ||||
|             <th scope="col"></th> | ||||
|         </template> | ||||
|         <template v-slot:tbody> | ||||
|             <tr v-for="(w, i) in workflows.results" :key="`workflow-${i}`"> | ||||
|                 <td>{{ w.title }}</td> | ||||
|                 <td> | ||||
|                     <div class="workflow"> | ||||
|                         <div class="breadcrumb"> | ||||
|                             <i class="fa fa-circle me-1 text-chill-yellow mx-2"></i> | ||||
|                             <span class="mx-2">{{ getStep(w) }}</span> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </td> | ||||
|                 <td v-if="w.datas.persons !== null"> | ||||
|                     <span v-for="p in w.datas.persons" class="me-1" :key="p.id"> | ||||
|                         <on-the-fly | ||||
|                             :type="p.type" | ||||
|                             :id="p.id" | ||||
|                             :buttonText="p.textAge" | ||||
|                             :displayBadge="'true' === 'true'" | ||||
|                             action="show"> | ||||
|                         </on-the-fly> | ||||
|                     </span> | ||||
|                 </td> | ||||
|                 <td> | ||||
|                 <a class="btn btn-sm btn-show" :href="getUrl(w)"> | ||||
|                     {{ $t('show_entity', { entity: $t('the_workflow') }) }} | ||||
|                 </a> | ||||
|                 </td> | ||||
|             </tr> | ||||
|         </template> | ||||
|     </tab-table> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapGetters } from "vuex"; | ||||
| import TabTable from "./TabTable"; | ||||
| import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly'; | ||||
|  | ||||
| export default { | ||||
|     name: "MyWorkflows", | ||||
|     components: { | ||||
|         TabTable, | ||||
|         OnTheFly | ||||
|     }, | ||||
|     props: ['workflows'], | ||||
|     computed: { | ||||
|         ...mapGetters([ | ||||
|             'isWorkflowsLoaded', | ||||
|         ]), | ||||
|     }, | ||||
|     methods: { | ||||
|         hasNoResults(workflows) { | ||||
|             if (!this.isWorkflowsLoaded) { | ||||
|                 return false; | ||||
|             } else { | ||||
|                 return workflows.count === 0; | ||||
|             } | ||||
|         }, | ||||
|         getUrl(w) { | ||||
|             return `/fr/main/workflow/${w.id}/show`; | ||||
|         }, | ||||
|         getStep(w) { | ||||
|             const lastStep = w.steps.length - 1 | ||||
|             return w.steps[lastStep].currentStep.text; | ||||
|         } | ||||
|     }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| span.outdated { | ||||
|     font-weight: bold; | ||||
|     color: var(--bs-warning); | ||||
| } | ||||
| </style> | ||||
| @@ -24,7 +24,8 @@ const appMessages = { | ||||
|         }, | ||||
|         my_workflows: { | ||||
|             tab: "Mes workflows", | ||||
|             description: "Liste des workflows en attente d'une action." | ||||
|             description: "Liste des workflows en attente d'une action.", | ||||
|             description_cc: "Liste des workflows dont je suis en copie." | ||||
|         }, | ||||
|         opening_date: "Date d'ouverture", | ||||
|         social_issues: "Problématiques sociales", | ||||
|   | ||||
| @@ -22,6 +22,7 @@ const store = createStore({ | ||||
|         accompanyingCourses: {}, | ||||
|         notifications: {}, | ||||
|         workflows: {}, | ||||
|         workflowsCc: {}, | ||||
|         errorMsg: [], | ||||
|         loading: false | ||||
|     }, | ||||
| @@ -87,6 +88,9 @@ const store = createStore({ | ||||
|         addWorkflows(state, workflows) { | ||||
|             state.workflows = workflows; | ||||
|         }, | ||||
|         addWorkflowsCc(state, workflows) { | ||||
|             state.workflowsCc = workflows; | ||||
|         }, | ||||
|         setLoading(state, bool) { | ||||
|             state.loading = bool; | ||||
|         }, | ||||
| @@ -195,17 +199,23 @@ const store = createStore({ | ||||
|                 case 'MyWorkflows': | ||||
|                     if (!getters.isWorflowsLoaded) { | ||||
|                         commit('setLoading', true); | ||||
|                         const url = '/api/1.0/main/workflow/my'; | ||||
|                         makeFetch('GET', url) | ||||
|                         .then((response) => { | ||||
|                             console.log('workflows', response) | ||||
|                             commit('addWorkflows', response); | ||||
|                             commit('setLoading', false); | ||||
|                         }) | ||||
|                         .catch((error) => { | ||||
|                             commit('catchError', error); | ||||
|                             throw error; | ||||
|                         }); | ||||
|                         makeFetch('GET', '/api/1.0/main/workflow/my') | ||||
|                             .then((response) => { | ||||
|                                 commit('addWorkflows', response); | ||||
|                                 makeFetch('GET', '/api/1.0/main/workflow/my-cc') | ||||
|                                     .then((response) => { | ||||
|                                         commit('addWorkflowsCc', response); | ||||
|                                         commit('setLoading', false); | ||||
|                                     }) | ||||
|                                     .catch((error) => { | ||||
|                                         commit('catchError', error); | ||||
|                                         throw error; | ||||
|                                     }); | ||||
|                             }) | ||||
|                             .catch((error) => { | ||||
|                                 commit('catchError', error); | ||||
|                                 throw error; | ||||
|                             }); | ||||
|                     } | ||||
|                     break; | ||||
|                 default: | ||||
|   | ||||
| @@ -30,11 +30,27 @@ | ||||
|                 {% endif %} | ||||
|                 {% if c.notification.addressees|length > 0 %} | ||||
|                     <li class="notification-to"> | ||||
|                         <span class="item-key"> | ||||
|                         {% if c.notification_cc is defined %} | ||||
|                             {% if c.notification_cc %} | ||||
|                             <span class="item-key"> | ||||
|                                 <abbr title="{{ 'notification.sent_cc'|trans }}"> | ||||
|                                     {{ 'notification.cc'|trans }} : | ||||
|                                 </abbr> | ||||
|                             </span> | ||||
|                             {% else %} | ||||
|                             <span class="item-key"> | ||||
|                                 <abbr title="{{ 'notification.sent_to'|trans }}"> | ||||
|                                     {{ 'notification.to'|trans }} : | ||||
|                                 </abbr> | ||||
|                             </span> | ||||
|                             {% endif %} | ||||
|                         {% else %} | ||||
|                           <span class="item-key"> | ||||
|                             <abbr title="{{ 'notification.sent_to'|trans }}"> | ||||
|                                 {{ 'notification.to'|trans }} : | ||||
|                             </abbr> | ||||
|                         </span> | ||||
|                         {% endif %} | ||||
|                         {% for a in c.notification.addressees %} | ||||
|                             <span class="badge-user"> | ||||
|                                 {{ a|chill_entity_render_string }} | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
|             'full_content': true, | ||||
|             'fold_item': true, | ||||
|             'action_button': true, | ||||
|             'notification_cc': notificationCc, | ||||
|         } %}{# | ||||
|     #} | ||||
|     {% endfor %} | ||||
|   | ||||
| @@ -50,7 +50,8 @@ | ||||
|             {% for data in datas %} | ||||
|                 {% set notification = data.notification %} | ||||
|                 {% include 'ChillMainBundle:Notification:_list_item.html.twig' with { | ||||
|                     'fold_item': true | ||||
|                     'fold_item': true, | ||||
|                     'notification_cc': data.isNotificationCc | ||||
|                 } %} | ||||
|             {% endfor %} | ||||
|         </div> | ||||
|   | ||||
| @@ -27,7 +27,8 @@ | ||||
|             }, | ||||
|             'action_button': false, | ||||
|             'full_content': true, | ||||
|             'fold_item': false | ||||
|             'fold_item': false, | ||||
|             'notification_cc': notificationCc | ||||
|         } %} | ||||
|     </div> | ||||
|  | ||||
|   | ||||
| @@ -65,6 +65,8 @@ | ||||
|     <div id="futureDests"> | ||||
|         {{ form_row(transition_form.future_dest_users) }} | ||||
|  | ||||
|         {{ form_row(transition_form.future_cc_users) }} | ||||
|  | ||||
|         {{ form_row(transition_form.future_dest_emails) }} | ||||
|     </div> | ||||
|  | ||||
|   | ||||
| @@ -81,6 +81,15 @@ | ||||
|                             </ul> | ||||
|                         {% endif %} | ||||
|  | ||||
|                         {% if step.ccUser|length > 0 %} | ||||
|                             <p><b>{{ 'workflow.Users put in Cc'|trans }} : </b></p> | ||||
|                             <ul> | ||||
|                                 {% for u in step.ccUser %} | ||||
|                                     <li>{{ u|chill_entity_render_box }}</li> | ||||
|                                 {% endfor %} | ||||
|                             </ul> | ||||
|                         {% endif %} | ||||
|  | ||||
|                         {% if entity_workflow.currentStep.destEmail|length > 0 %} | ||||
|                             <p><b>{{ 'workflow.An access key was also sent to those addresses'|trans }} :</b></p> | ||||
|                             <ul> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| {% endblock %} | ||||
|  | ||||
| {% block content %} | ||||
| <div class="col-10 workflow"> | ||||
| <div class="col-12 workflow"> | ||||
|  | ||||
|     <h1 class="mb-5">{{ block('title') }}</h1> | ||||
|  | ||||
| @@ -25,6 +25,12 @@ | ||||
|                 {{ 'workflow.dest'|trans }} | ||||
|             </a> | ||||
|         </li> | ||||
|         <li class="nav-item"> | ||||
|             <a href="{{ path('chill_main_workflow_list_cc') }}" | ||||
|                 class="nav-link {% if step == 'cc' %}active{% endif %}"> | ||||
|                 {{ 'workflow.cc'|trans }} | ||||
|             </a> | ||||
|         </li> | ||||
|         <li class="nav-item"> | ||||
|             <a href="{{ path('chill_main_workflow_list_previous_without_reaction') }}" | ||||
|                class="nav-link {% if step == 'previous_without_reaction' %}active{% endif %}"> | ||||
|   | ||||
| @@ -15,6 +15,12 @@ | ||||
|                     {% for d in step.destUser %}{{ d|chill_entity_render_string }}{% if not loop.last %}, {% endif %}{% endfor %} | ||||
|                 </b> | ||||
|             </li> | ||||
|             <li> | ||||
|                 <span class="item-key">{{ 'workflow.Cc'|trans ~ ' : ' }}</span> | ||||
|                 <b> | ||||
|                     {% for u in step.ccUser %}{{ u|chill_entity_render_string }}{% if not loop.last %}, {% endif %}{% endfor %} | ||||
|                 </b> | ||||
|             </li> | ||||
|         {% else %} | ||||
|             <li> | ||||
|                 <span class="item-key">{{ 'workflow.Created by'|trans ~ ' : ' }}</span> | ||||
|   | ||||
| @@ -50,6 +50,10 @@ class EntityWorkflowTransitionEventSubscriber implements EventSubscriberInterfac | ||||
|         /** @var EntityWorkflow $entityWorkflow */ | ||||
|         $entityWorkflow = $event->getSubject(); | ||||
|  | ||||
|         foreach ($entityWorkflow->futureCcUsers as $user) { | ||||
|             $entityWorkflow->getCurrentStep()->addCcUser($user); | ||||
|         } | ||||
|  | ||||
|         foreach ($entityWorkflow->futureDestUsers as $user) { | ||||
|             $entityWorkflow->getCurrentStep()->addDestUser($user); | ||||
|         } | ||||
|   | ||||
| @@ -85,7 +85,9 @@ class NotificationOnTransition implements EventSubscriberInterface | ||||
|             // the subscriber to final, only if final | ||||
|             $entityWorkflow->isFinal() ? $entityWorkflow->getSubscriberToFinal()->toArray() : [], | ||||
|             // the dests for the current step | ||||
|             $entityWorkflow->getCurrentStep()->getDestUser()->toArray() | ||||
|             $entityWorkflow->getCurrentStep()->getDestUser()->toArray(), | ||||
|             // the cc users for the current step | ||||
|             $entityWorkflow->getCurrentStep()->getCcUser()->toArray() | ||||
|         ) as $dest) { | ||||
|             $dests[spl_object_hash($dest)] = $dest; | ||||
|         } | ||||
|   | ||||
| @@ -826,4 +826,20 @@ paths: | ||||
|                                     $ref: '#/components/schemas/Workflow' | ||||
|                 403: | ||||
|                     description: "Unauthorized" | ||||
|     /1.0/main/workflow/my-cc: | ||||
|         get: | ||||
|             tags: | ||||
|                 - workflow | ||||
|             summary: Return a list of workflows for which user was notified in Cc | ||||
|             responses: | ||||
|                 200: | ||||
|                     description: "ok" | ||||
|                     content: | ||||
|                         application/json: | ||||
|                             schema: | ||||
|                                 type: array | ||||
|                                 items: | ||||
|                                     $ref: '#/components/schemas/Workflow' | ||||
|                 403: | ||||
|                     description: "Unauthorized" | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,39 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * 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. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\Migrations\Main; | ||||
|  | ||||
| use Doctrine\DBAL\Schema\Schema; | ||||
| use Doctrine\Migrations\AbstractMigration; | ||||
|  | ||||
| final class Version20230321134155 extends AbstractMigration | ||||
| { | ||||
|     public function down(Schema $schema): void | ||||
|     { | ||||
|         $this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user DROP CONSTRAINT FK_9FC79037E6AF9D4'); | ||||
|         $this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user DROP CONSTRAINT FK_9FC7903A76ED395'); | ||||
|         $this->addSql('DROP TABLE chill_main_workflow_entity_step_cc_user'); | ||||
|     } | ||||
|  | ||||
|     public function getDescription(): string | ||||
|     { | ||||
|         return 'Add cc User to workflow step'; | ||||
|     } | ||||
|  | ||||
|     public function up(Schema $schema): void | ||||
|     { | ||||
|         $this->addSql('CREATE TABLE chill_main_workflow_entity_step_cc_user (entityworkflowstep_id INT NOT NULL, user_id INT NOT NULL, PRIMARY KEY(entityworkflowstep_id, user_id))'); | ||||
|         $this->addSql('CREATE INDEX IDX_9FC79037E6AF9D4 ON chill_main_workflow_entity_step_cc_user (entityworkflowstep_id)'); | ||||
|         $this->addSql('CREATE INDEX IDX_9FC7903A76ED395 ON chill_main_workflow_entity_step_cc_user (user_id)'); | ||||
|         $this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user ADD CONSTRAINT FK_9FC79037E6AF9D4 FOREIGN KEY (entityworkflowstep_id) REFERENCES chill_main_workflow_entity_step (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); | ||||
|         $this->addSql('ALTER TABLE chill_main_workflow_entity_step_cc_user ADD CONSTRAINT FK_9FC7903A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); | ||||
|     } | ||||
| } | ||||
| @@ -447,6 +447,7 @@ workflow: | ||||
|     Created by: Créé par | ||||
|     My decision: Ma décision | ||||
|     Next step: Prochaine étape | ||||
|     cc for next steps: Utilisateurs en copie | ||||
|     dest for next steps: Utilisateurs qui valideront la prochaine étape | ||||
|     Freeze: Geler | ||||
|     Freezed: Gelé | ||||
| @@ -465,12 +466,14 @@ workflow: | ||||
|     Document (n°%doc%): "Document (n°%doc%)" | ||||
|     Work (n°%w%): "Action d'accompagnement (n°%w%)" | ||||
|     subscribed: Workflows suivis | ||||
|     cc: Workflows dont je suis en copie | ||||
|     dest: Workflows en attente d'action | ||||
|     you subscribed to all steps: Vous recevrez une notification à chaque étape | ||||
|     you subscribed to final step: Vous recevrez une notification à l'étape finale | ||||
|     Current step: Étape actuelle | ||||
|     Comment on last change: Commentaire à la transition précédente | ||||
|     Users allowed to apply transition: Utilisateurs pouvant valider cette étape | ||||
|     Users put in Cc: Utilisateurs mis en copie | ||||
|     Workflow deleted with success: Le workflow a été supprimé | ||||
|     Delete workflow ?: Supprimer le workflow ? | ||||
|     Are you sure you want to delete this workflow ?: Êtes-vous sûr·e de vouloir supprimer ce workflow ? | ||||
| @@ -487,6 +490,7 @@ workflow: | ||||
|     Previous transitionned: Anciens workflows | ||||
|     Previous workflow transitionned help: Workflows où vous avez exécuté une action. | ||||
|     For: Pour | ||||
|     Cc: Cc | ||||
|     You must select a next step, pick another decision if no next steps are available: Il faut une prochaine étape. Choissisez une autre décision si nécessaire. | ||||
|     An access key was also sent to those addresses: Un lien d'accès a été envoyé à ces adresses | ||||
|     Those users are also granted to apply a transition by using an access key: Ces utilisateurs ont obtenu l'accès grâce au lien reçu par email | ||||
| @@ -521,7 +525,9 @@ notification: | ||||
|     list: Notifications | ||||
|     Sent: Envoyé | ||||
|     to: À | ||||
|     cc: Cc | ||||
|     sent_to: Destinataire(s) | ||||
|     sent_cc: En copie | ||||
|     from: De | ||||
|     received_from: Expéditeur | ||||
|     you were notified by %sender%:  Vous avez été notifié par %sender% | ||||
|   | ||||
| @@ -373,6 +373,7 @@ workflow: | ||||
|     Created by: Créé par | ||||
|     My decision: Ma décision | ||||
|     Next step: Prochaine étape | ||||
|     cc for next steps: Utilisateurs en copie | ||||
|     dest for next steps: Utilisateurs qui valideront la prochaine étape | ||||
|     Freeze: Geler | ||||
|     Freezed: Gelé | ||||
| @@ -392,11 +393,13 @@ workflow: | ||||
|     Work (n°%w%): "Action d'accompagnement (n°%w%)" | ||||
|     subscribed: Workflows suivis | ||||
|     dest: Workflows en attente d'action | ||||
|     cc: Workflows dont je suis en copie | ||||
|     you subscribed to all steps: Vous recevrez une notification à chaque étape | ||||
|     you subscribed to final step: Vous recevrez une notification à l'étape finale | ||||
|     Current step: Étape actuelle | ||||
|     Comment on last change: Commentaire à la transition précédente | ||||
|     Users allowed to apply transition: Utilisateurs pouvant valider cette étape | ||||
|     Users put in Cc: Utilisateurs mis en copie | ||||
|     Workflow deleted with success: Le workflow a été supprimé | ||||
|     Delete workflow ?: Supprimer le workflow ? | ||||
|     Are you sure you want to delete this workflow ?: Êtes-vous sûr·e de vouloir supprimer ce workflow ? | ||||
| @@ -414,6 +417,7 @@ workflow: | ||||
|     Previous transitionned: Anciens workflows | ||||
|     Previous workflow transitionned help: Workflows où vous avez exécuté une action. | ||||
|     For: Pour | ||||
|     Cc: Cc | ||||
|  | ||||
|  | ||||
| Subscribe final: Recevoir une notification à l'étape finale | ||||
| @@ -442,7 +446,9 @@ notification: | ||||
|     list: Notifications | ||||
|     Sent: Envoyé | ||||
|     to: À | ||||
|     cc: Cc | ||||
|     sent_to: Destinataire(s) | ||||
|     sent_cc: En copie | ||||
|     from: De | ||||
|     received_from: Expéditeur | ||||
|     you were notified by %sender%:  Vous avez été notifié par %sender% | ||||
|   | ||||
		Reference in New Issue
	
	Block a user