mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-04 11:18:25 +00:00 
			
		
		
		
	Compare commits
	
		
			232 Commits
		
	
	
		
			20-update-
			...
			issue444_m
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bb86d04e52 | |||
| 4c704734cd | |||
| 0ffd6a857c | |||
| aebb21935b | |||
| f2221565c5 | |||
| 9ead38ee22 | |||
| 6402962990 | |||
| 9e9fa5039f | |||
| e6d503a1e2 | |||
| 4920142540 | |||
| 61cf838458 | |||
| e028c1ca2b | |||
| 7dd6cd04ba | |||
| 1072f539dc | |||
| 9bcf4cce9f | |||
| 9223beac47 | |||
| 62c78e650f | |||
| e7d0c1cac6 | |||
| b859283766 | |||
| e595500cb8 | |||
| f34847f9f6 | |||
| 0fa119c984 | |||
| 270d00c1e8 | |||
| 983c5f3c6a | |||
| c6141e473f | |||
| c30cb5879d | |||
| 29e384ada5 | |||
| c8e5ba4738 | |||
| bf0b7f1bb2 | |||
| d6cc69b919 | |||
| ac33c6aad8 | |||
| 89383a5ec4 | |||
| 0fd26da299 | |||
| 6fa99655b2 | |||
| a387305ef8 | |||
| e0c7daf3fd | |||
| 4304baeca5 | |||
| d2a567c79e | |||
| 3c04ced1a3 | |||
| a28d8a7287 | |||
| 1c055e842e | |||
| dea283d655 | |||
| 58c8373c81 | |||
| a1ccfadac1 | |||
| 632b1262f9 | |||
| e157624479 | |||
| 3a2370d536 | |||
| 
						 | 
					eee38e9577 | ||
| 981c94906d | |||
| adce90c151 | |||
| 83f8402081 | |||
| 22417ee9f9 | |||
| 3c5d269ece | |||
| 42579b5752 | |||
| 15023d348a | |||
| fbf777e134 | |||
| 450277f32a | |||
| 
						 | 
					1f5d529d33 | ||
| 93128cb61b | |||
| 
						 | 
					c19099e76c | ||
| d3d655293e | |||
| 
						 | 
					692343aae4 | ||
| 0592601aa6 | |||
| a17f5948fb | |||
| 
						 | 
					4dd9bc1123 | ||
| 6578f66fec | |||
| 3f2a19a6f0 | |||
| d5160ead4c | |||
| a6e9cbdece | |||
| 657bf7075b | |||
| f1c3e8dc1b | |||
| a9624b36f7 | |||
| db4aec9a18 | |||
| c34ce48a53 | |||
| 93345c09a1 | |||
| b5a1985fa1 | |||
| 9b4c350213 | |||
| 199a441593 | |||
| f42d106e3c | |||
| 13eddbfc5b | |||
| 7c30126fed | |||
| e3c5f6f95f | |||
| a86f1a05ac | |||
| 9ba0cb0c2a | |||
| add8588767 | |||
| a083a320ae | |||
| 64fa7f2e00 | |||
| c7a830ee28 | |||
| 9aa51406fa | |||
| 344981cf99 | |||
| 28c4d6b92f | |||
| ef2ab5faf6 | |||
| 54dbf711f9 | |||
| 60951231c4 | |||
| ece30b63c3 | |||
| 94503505f7 | |||
| 48589f3368 | |||
| 1e04c178dc | |||
| 37ed703abe | |||
| 7ed20d2fc5 | |||
| 5fe2a8e737 | |||
| 
						 | 
					861abe708b | ||
| 
						 | 
					f43e216e13 | ||
| 5210e7985f | |||
| ddabdff206 | |||
| 5a692db30f | |||
| 659983fef1 | |||
| aca5a3c731 | |||
| 406cfc86cd | |||
| 90da067fbd | |||
| e7a6742964 | |||
| 3ffeaf419a | |||
| ce2f64acd0 | |||
| 08f544f6ea | |||
| 4e862cc585 | |||
| 05d2c3b2e8 | |||
| 513207e510 | |||
| dee6ed6707 | |||
| d60095987c | |||
| b4f9be0d92 | |||
| a2a0f6af44 | |||
| 7fa0353d8c | |||
| 9256c71715 | |||
| 5520f3df50 | |||
| a6c0d8b219 | |||
| f6e667700e | |||
| f94ef0798a | |||
| 7bd7476200 | |||
| a2752765af | |||
| 1e81256404 | |||
| 6b571e87b4 | |||
| 4314823a70 | |||
| dc08ced6c9 | |||
| 9d660311f0 | |||
| b3e65f0733 | |||
| 03007370bc | |||
| f9b514c869 | |||
| 
						 | 
					91ba08dfa1 | ||
| 
						 | 
					06142797c3 | ||
| 
						 | 
					4185b660cc | ||
| ad46776164 | |||
| 2343a4a334 | |||
| 3f83c323be | |||
| 9a9ed64298 | |||
| 
						 | 
					a0cadb46db | ||
| 
						 | 
					f139af8b6f | ||
| 
						 | 
					1f0ef6e187 | ||
| 
						 | 
					4afea55465 | ||
| 
						 | 
					3d5723facb | ||
| 211ecf1c3e | |||
| 796b4ff76b | |||
| 9553e18d83 | |||
| 02d9a713de | |||
| 6cc4fa582e | |||
| b8d43f36eb | |||
| 06b3d63133 | |||
| 232e71f46c | |||
| 0b5a0e65a8 | |||
| ef42227e6c | |||
| 2af3de4f61 | |||
| 8bafa37fe1 | |||
| 
						 | 
					a83b0326d7 | ||
| 53e03395f2 | |||
| 5fef4048a4 | |||
| d8929a6222 | |||
| 33af7f36a0 | |||
| 3f2454cead | |||
| 0ac9f2df8c | |||
| 333224a9d5 | |||
| 496e5f0259 | |||
| f2a62822a4 | |||
| 7879a99197 | |||
| 72d8cc297f | |||
| 1a0674a20b | |||
| 572aa2c14e | |||
| bc4b2c4e86 | |||
| a227e88e79 | |||
| d9e9f472fb | |||
| fcff4bf863 | |||
| 79b82e09e1 | |||
| 
						 | 
					a78f29cffc | ||
| e98b1b049b | |||
| 99efa51794 | |||
| 76932e6e8c | |||
| 97d2e3d5b5 | |||
| a2063ab13b | |||
| 2bb718f3ea | |||
| c6373a075d | |||
| 46337ef25d | |||
| 2f5fecf414 | |||
| 5d2cb8c712 | |||
| 460502a1f2 | |||
| cdd7a16d18 | |||
| ec29758547 | |||
| c5cbdd97ff | |||
| 05fc5a1829 | |||
| c3de3c6c39 | |||
| 1530e9d13a | |||
| a986b4ae98 | |||
| 0854b7fc6a | |||
| 730199cca4 | |||
| de1dddbb85 | |||
| a612d7dd9f | |||
| 50e722e637 | |||
| e4d5e40a8b | |||
| 479ec25d99 | |||
| 930b6ff77e | |||
| 7d8bd089a2 | |||
| 2c566bb21c | |||
| a0bc6c7604 | |||
| a4457664d4 | |||
| b42ae76bdf | |||
| 2eb1ebd263 | |||
| b79885cd21 | |||
| 69dd920fd6 | |||
| 0689ca366d | |||
| af1c268784 | |||
| 1162c436c1 | |||
| 571a8a0edc | |||
| bdbb83ab85 | |||
| 434d672d8a | |||
| e21ff588ae | |||
| 0383571a9e | |||
| f358e78734 | |||
| 43ef31b93f | |||
| 15393d9da9 | |||
| 695d22adba | |||
| bc1a63354c | |||
| faebb0fe30 | |||
| 68d99050bc | |||
| 4fa1bb4341 | |||
| 739540af64 | 
							
								
								
									
										64
									
								
								.env
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								.env
									
									
									
									
									
								
							@@ -1,64 +0,0 @@
 | 
			
		||||
##
 | 
			
		||||
##  Manually dump .env files in .env.local.php with
 | 
			
		||||
## `$ composer symfony:dump-env prod`
 | 
			
		||||
##
 | 
			
		||||
 | 
			
		||||
## Project environment
 | 
			
		||||
APP_ENV=dev
 | 
			
		||||
 | 
			
		||||
## Enable debug
 | 
			
		||||
APP_DEBUG=true
 | 
			
		||||
 | 
			
		||||
## Locale
 | 
			
		||||
LOCALE=fr
 | 
			
		||||
 | 
			
		||||
## Framework secret
 | 
			
		||||
APP_SECRET=ThisTokenIsNotSoSecretChangeIt
 | 
			
		||||
 | 
			
		||||
## Symfony/swiftmailer
 | 
			
		||||
MAILER_TRANSPORT=smtp
 | 
			
		||||
MAILER_HOST=smtp
 | 
			
		||||
MAILER_PORT=1025
 | 
			
		||||
MAILER_CRYPT=
 | 
			
		||||
MAILER_AUTH=
 | 
			
		||||
MAILER_USER=
 | 
			
		||||
MAILER_PASSWORD=
 | 
			
		||||
MAILER_URL=${MAILER_TRANSPORT}://${MAILER_HOST}:${MAILER_PORT}?encryption=${MAILER_CRYPT}&auth_mode=${MAILER_AUTH}&username=${MAILER_USER}&password=${MAILER_PASSWORD}
 | 
			
		||||
 | 
			
		||||
## Notifications
 | 
			
		||||
NOTIFICATION_HOST=localhost:8001
 | 
			
		||||
NOTIFICATION_FROM_EMAIL=admin@chill.social
 | 
			
		||||
NOTIFICATION_FROM_NAME=Chill
 | 
			
		||||
 | 
			
		||||
## Gelf
 | 
			
		||||
GELF_HOST=gelf
 | 
			
		||||
GELF_PORT=12201
 | 
			
		||||
 | 
			
		||||
## OVH OpenStack Storage User/Role
 | 
			
		||||
OS_USERNAME=
 | 
			
		||||
OS_PASSWORD=
 | 
			
		||||
OS_TENANT_ID=
 | 
			
		||||
OS_REGION_NAME=GRA
 | 
			
		||||
OS_AUTH_URL=https://auth.cloud.ovh.net/v2.0/
 | 
			
		||||
 | 
			
		||||
## OVH OpenStack Storage Container
 | 
			
		||||
ASYNC_UPLOAD_TEMP_URL_KEY=
 | 
			
		||||
ASYNC_UPLOAD_TEMP_URL_BASE_PATH=
 | 
			
		||||
ASYNC_UPLOAD_TEMP_URL_CONTAINER=
 | 
			
		||||
 | 
			
		||||
## Redis Cache
 | 
			
		||||
REDIS_HOST=redis
 | 
			
		||||
REDIS_PORT=6379
 | 
			
		||||
REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}
 | 
			
		||||
 | 
			
		||||
## Twilio
 | 
			
		||||
TWILIO_SID=~
 | 
			
		||||
TWILIO_SECRET=~
 | 
			
		||||
 | 
			
		||||
## DOCKER IMAGES REGISTRY
 | 
			
		||||
#IMAGE_PHP=
 | 
			
		||||
#IMAGE_NGINX=
 | 
			
		||||
 | 
			
		||||
## DOCKER IMAGES VERSION
 | 
			
		||||
#VERSION=test
 | 
			
		||||
VERSION=prod
 | 
			
		||||
							
								
								
									
										54
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -11,16 +11,57 @@ and this project adheres to
 | 
			
		||||
## Unreleased
 | 
			
		||||
 | 
			
		||||
<!-- write down unreleased development here -->
 | 
			
		||||
* renommer "dossier numéro" en "parcours numéro" dans les résultats de recherche
 | 
			
		||||
* renomme date de début en date d'ouverture dans le formulaire parcours
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Test releases
 | 
			
		||||
 | 
			
		||||
### test release 2022-02-14
 | 
			
		||||
 | 
			
		||||
* AddPersons: remove ul-li html tags from AddPersons (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/419)
 | 
			
		||||
* [doc-generator] do not set required fields for mainPerson, person1, person2 (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement#456)
 | 
			
		||||
* [doc-generation] add age and obele in the mainPerson, person1 and person2 list + add obele in person renderString if addAge (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/370)
 | 
			
		||||
* [person] accompanying course work: fix on-the-fly update of thirdParty
 | 
			
		||||
* fix normalisation of accompanying course requestor api (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/378)
 | 
			
		||||
* [person] add a returnPath when clicking on some Person or ThirdParty badge (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/427)
 | 
			
		||||
* [person] accompanying course work: fix on-the-fly update of thirdParty 
 | 
			
		||||
* [on-the-fly] close modal only after validation
 | 
			
		||||
* [person] correct thirdparty PATCH url + add email and altnames in AddPerson and serializer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/433)
 | 
			
		||||
* change order for accompanying course work list
 | 
			
		||||
* [parcours]: Mes parcours brouillon added to user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/440)
 | 
			
		||||
* [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414)
 | 
			
		||||
* [person]: style fix in parcours listing per person. (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/432)
 | 
			
		||||
* [household]: display address of current household (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/415)
 | 
			
		||||
* ajoute un ordre dans les localisation (api)
 | 
			
		||||
* [pick entity]: fix translations in modal (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/419)
 | 
			
		||||
* [homepage_widget]: fix translation on emergency badge (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/440)
 | 
			
		||||
* [person]: create person and household added to button dropdown (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/454)
 | 
			
		||||
* display full address in address.text in normalization. Adapt AddressRenderBox
 | 
			
		||||
* [address]: Correction residential address 'depuis le' (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/459)
 | 
			
		||||
* [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414)
 | 
			
		||||
* [Thirdparty_contact]: address blurred if confidential in view page (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/450)
 | 
			
		||||
* [homepage_widget]: If no sender then display as 'notification automatique' (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/435)
 | 
			
		||||
 | 
			
		||||
### test release 2021-02-01
 | 
			
		||||
 | 
			
		||||
* renommer "dossier numéro" en "parcours numéro" dans les résultats de recherche
 | 
			
		||||
* renomme date de début en date d'ouverture dans le formulaire parcours
 | 
			
		||||
* [homepage widget] improve content tables, improve counter pluralization with style on number
 | 
			
		||||
* [notification lists] add comments counter information
 | 
			
		||||
* [workflows] fix popover header with previous transition
 | 
			
		||||
* [parcours]: validation + message for closing parcours adjusted.
 | 
			
		||||
* [household]: household composition double edit button replaced by a delete action (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/426)
 | 
			
		||||
[fast_actions] improve fast-actions buttons override mechanism, fix https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/413
 | 
			
		||||
[homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc.
 | 
			
		||||
* [person]: Comment on marital status is possible even if marital status is not defined (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/421)
 | 
			
		||||
* [parcours]: In the list of person results the requestor is not displayed if defined as anonymous (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/424)
 | 
			
		||||
* [bugfix]: modal closes and newly created person/thirdparty is selected when multiple persons/thirdparties are created through the modal (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/429)
 | 
			
		||||
* [person_resource]: Onthefly button added to view person/thirdparty and badge differentiation for a contact-thirdparty (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/428)
 | 
			
		||||
* [workflow][notification] improve how notifications and workflows are 'attached' to entities: contextual list, counter, buttons and vue modal
 | 
			
		||||
* [AddAddress] disable multiselect search, and rely only on most pertinent Cities and Street computed backend
 | 
			
		||||
* [fast_actions] improve fast-actions buttons override mechanism, fix https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/413
 | 
			
		||||
* [homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc.
 | 
			
		||||
 | 
			
		||||
### test release 2021-01-31
 | 
			
		||||
 | 
			
		||||
[fast_actions] improve fast-actions buttons override mechanism, fix https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/413
 | 
			
		||||
[homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc.  
 | 
			
		||||
* [person] accompanying course: optimisation: do not fetch some resources for the banner (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/409)
 | 
			
		||||
* [person] accompanying course: close modal when edit participation (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/420)
 | 
			
		||||
* [person] accompanying course: treat validation error when editing on-the-fly entities (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/420)
 | 
			
		||||
@@ -31,7 +72,6 @@ and this project adheres to
 | 
			
		||||
* [user]: page with accompanying periods to which is user is referent (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/408)
 | 
			
		||||
* [person] age added to renderstring + renderbox/ vue component created to display person text (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/389)
 | 
			
		||||
* [household member editor] allow to push to existing household
 | 
			
		||||
* [workflow][notification] improve how notifications and workflows are 'attached' to entities: contextual list, counter, buttons and vue modal
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### test release 2021-01-28
 | 
			
		||||
@@ -67,7 +107,7 @@ and this project adheres to
 | 
			
		||||
* [popover] add popover html popup mechanism (used by workflow breadcrumb)
 | 
			
		||||
* [templates] improve updatedBy macro in item metadatas
 | 
			
		||||
* [parcours]: bug fix when comment is pinned all other comments remain in the collection (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/385)
 | 
			
		||||
* [workflow] 
 | 
			
		||||
* [workflow]
 | 
			
		||||
  * add My workflow section with my opened subscriptions
 | 
			
		||||
  * apply workflow on documents, accompanyingCourseWork and Evaluations
 | 
			
		||||
* [wopi-link] a new vue component allow to open wopi link in a fullscreen chill-themed modal
 | 
			
		||||
 
 | 
			
		||||
@@ -408,24 +408,6 @@ parameters:
 | 
			
		||||
			count: 1
 | 
			
		||||
			path: src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php
 | 
			
		||||
 | 
			
		||||
		-
 | 
			
		||||
			message:
 | 
			
		||||
				"""
 | 
			
		||||
					#^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\:
 | 
			
		||||
					Use getReachableCircles$#
 | 
			
		||||
				"""
 | 
			
		||||
			count: 1
 | 
			
		||||
			path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php
 | 
			
		||||
 | 
			
		||||
		-
 | 
			
		||||
			message:
 | 
			
		||||
				"""
 | 
			
		||||
					#^Parameter \\$translator of method Chill\\\\DocStoreBundle\\\\Controller\\\\DocumentPersonController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\:
 | 
			
		||||
					since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$#
 | 
			
		||||
				"""
 | 
			
		||||
			count: 1
 | 
			
		||||
			path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php
 | 
			
		||||
 | 
			
		||||
		-
 | 
			
		||||
			message:
 | 
			
		||||
				"""
 | 
			
		||||
@@ -927,15 +909,6 @@ parameters:
 | 
			
		||||
			count: 1
 | 
			
		||||
			path: src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php
 | 
			
		||||
 | 
			
		||||
		-
 | 
			
		||||
			message:
 | 
			
		||||
				"""
 | 
			
		||||
					#^Parameter \\$trans of method Chill\\\\PersonBundle\\\\Controller\\\\AccompanyingCourseWorkController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\:
 | 
			
		||||
					since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$#
 | 
			
		||||
				"""
 | 
			
		||||
			count: 1
 | 
			
		||||
			path: src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php
 | 
			
		||||
 | 
			
		||||
		-
 | 
			
		||||
			message:
 | 
			
		||||
				"""
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ use Psr\Log\LoggerInterface;
 | 
			
		||||
use RuntimeException;
 | 
			
		||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 | 
			
		||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 | 
			
		||||
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
 | 
			
		||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
 | 
			
		||||
use Symfony\Component\Form\FormInterface;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
@@ -200,12 +201,36 @@ final class ActivityController extends AbstractController
 | 
			
		||||
            'role' => new Role('CHILL_ACTIVITY_UPDATE'),
 | 
			
		||||
            'activityType' => $entity->getActivityType(),
 | 
			
		||||
            'accompanyingPeriod' => $accompanyingPeriod,
 | 
			
		||||
        ])->handleRequest($request);
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        if ($form->has('documents')) {
 | 
			
		||||
            $form->add('gendocTemplateId', HiddenType::class, [
 | 
			
		||||
                'mapped' => false,
 | 
			
		||||
                'data' => null,
 | 
			
		||||
                'attr' => [
 | 
			
		||||
                    // required for js
 | 
			
		||||
                    'data-template-id' => 'data-template-id',
 | 
			
		||||
                ],
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $form->handleRequest($request);
 | 
			
		||||
 | 
			
		||||
        if ($form->isSubmitted() && $form->isValid()) {
 | 
			
		||||
            $this->entityManager->persist($entity);
 | 
			
		||||
            $this->entityManager->flush();
 | 
			
		||||
 | 
			
		||||
            if ($form->has('gendocTemplateId') && null !== $form['gendocTemplateId']->getData()) {
 | 
			
		||||
                return $this->redirectToRoute(
 | 
			
		||||
                    'chill_docgenerator_generate_from_template',
 | 
			
		||||
                    [
 | 
			
		||||
                        'template' => $form->get('gendocTemplateId')->getData(),
 | 
			
		||||
                        'entityClassName' => Activity::class,
 | 
			
		||||
                        'entityId' => $entity->getId(),
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->addFlash('success', $this->get('translator')->trans('Success : activity updated!'));
 | 
			
		||||
 | 
			
		||||
            $params = $this->buildParamsToUrl($person, $accompanyingPeriod);
 | 
			
		||||
@@ -393,12 +418,36 @@ final class ActivityController extends AbstractController
 | 
			
		||||
            'role' => new Role('CHILL_ACTIVITY_CREATE'),
 | 
			
		||||
            'activityType' => $entity->getActivityType(),
 | 
			
		||||
            'accompanyingPeriod' => $accompanyingPeriod,
 | 
			
		||||
        ])->handleRequest($request);
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        if ($form->has('documents')) {
 | 
			
		||||
            $form->add('gendocTemplateId', HiddenType::class, [
 | 
			
		||||
                'mapped' => false,
 | 
			
		||||
                'data' => null,
 | 
			
		||||
                'attr' => [
 | 
			
		||||
                    // required for js
 | 
			
		||||
                    'data-template-id' => 'data-template-id',
 | 
			
		||||
                ],
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $form->handleRequest($request);
 | 
			
		||||
 | 
			
		||||
        if ($form->isSubmitted() && $form->isValid()) {
 | 
			
		||||
            $this->entityManager->persist($entity);
 | 
			
		||||
            $this->entityManager->flush();
 | 
			
		||||
 | 
			
		||||
            if ($form->has('gendocTemplateId') && null !== $form['gendocTemplateId']->getData()) {
 | 
			
		||||
                return $this->redirectToRoute(
 | 
			
		||||
                    'chill_docgenerator_generate_from_template',
 | 
			
		||||
                    [
 | 
			
		||||
                        'template' => $form->get('gendocTemplateId')->getData(),
 | 
			
		||||
                        'entityClassName' => Activity::class,
 | 
			
		||||
                        'entityId' => $entity->getId(),
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->addFlash('success', $this->get('translator')->trans('Success : activity created!'));
 | 
			
		||||
 | 
			
		||||
            $params = $this->buildParamsToUrl($person, $accompanyingPeriod);
 | 
			
		||||
 
 | 
			
		||||
@@ -271,7 +271,7 @@ class ActivityType
 | 
			
		||||
    public function checkSocialActionsVisibility(ExecutionContextInterface $context, $payload)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->socialIssuesVisible !== $this->socialActionsVisible) {
 | 
			
		||||
            if (!($this->socialIssuesVisible === 2 && $this->socialActionsVisible === 1)) {
 | 
			
		||||
            if (!(2 === $this->socialIssuesVisible && 1 === $this->socialActionsVisible)) {
 | 
			
		||||
                $context
 | 
			
		||||
                    ->buildViolation('The socialActionsVisible value is not compatible with the socialIssuesVisible value')
 | 
			
		||||
                    ->atPath('socialActionsVisible')
 | 
			
		||||
 
 | 
			
		||||
@@ -15,19 +15,13 @@ use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
 | 
			
		||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
 | 
			
		||||
use Knp\Menu\MenuItem;
 | 
			
		||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
 | 
			
		||||
use Symfony\Component\Translation\TranslatorInterface;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 | 
			
		||||
class PersonMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var AuthorizationCheckerInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $authorizationChecker;
 | 
			
		||||
    protected AuthorizationCheckerInterface $authorizationChecker;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TranslatorInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $translator;
 | 
			
		||||
    protected TranslatorInterface $translator;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        AuthorizationCheckerInterface $authorizationChecker,
 | 
			
		||||
 
 | 
			
		||||
@@ -19,14 +19,18 @@
 | 
			
		||||
         </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <add-persons
 | 
			
		||||
         buttonTitle="activity.add_persons"
 | 
			
		||||
         modalTitle="activity.add_persons"
 | 
			
		||||
         v-bind:key="addPersons.key"
 | 
			
		||||
         v-bind:options="addPersonsOptions"
 | 
			
		||||
         @addNewPersons="addNewPersons"
 | 
			
		||||
         ref="addPersons">
 | 
			
		||||
      </add-persons>
 | 
			
		||||
      <ul class="record_actions">
 | 
			
		||||
         <li class="add-persons">
 | 
			
		||||
            <add-persons
 | 
			
		||||
               buttonTitle="activity.add_persons"
 | 
			
		||||
               modalTitle="activity.add_persons"
 | 
			
		||||
               v-bind:key="addPersons.key"
 | 
			
		||||
               v-bind:options="addPersonsOptions"
 | 
			
		||||
               @addNewPersons="addNewPersons"
 | 
			
		||||
               ref="addPersons">
 | 
			
		||||
            </add-persons>
 | 
			
		||||
         </li>
 | 
			
		||||
      </ul>
 | 
			
		||||
 | 
			
		||||
   </teleport>
 | 
			
		||||
</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,15 @@ import { createApp } from 'vue';
 | 
			
		||||
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
 | 
			
		||||
import { activityMessages } from './i18n'
 | 
			
		||||
import store from './store'
 | 
			
		||||
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
 | 
			
		||||
import {fetchTemplates} from 'ChillDocGeneratorAssets/api/pickTemplate.js';
 | 
			
		||||
 | 
			
		||||
import App from './App.vue';
 | 
			
		||||
 | 
			
		||||
const i18n = _createI18n(activityMessages);
 | 
			
		||||
 | 
			
		||||
// app for activity
 | 
			
		||||
 | 
			
		||||
const hasSocialIssues = document.querySelector('#social-issues-acc') !== null;
 | 
			
		||||
const hasLocation = document.querySelector('#location') !== null;
 | 
			
		||||
const hasPerson = document.querySelector('#add-persons') !== null;
 | 
			
		||||
@@ -29,3 +33,54 @@ const app = createApp({
 | 
			
		||||
.use(i18n)
 | 
			
		||||
.component('app', App)
 | 
			
		||||
.mount('#activity');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// app for picking template
 | 
			
		||||
 | 
			
		||||
const i18nGendoc = _createI18n({});
 | 
			
		||||
 | 
			
		||||
document.querySelectorAll('div[data-docgen-template-picker]').forEach(el => {
 | 
			
		||||
    fetchTemplates(el.dataset.entityClass).then(templates => {
 | 
			
		||||
        const picker = {
 | 
			
		||||
            template:
 | 
			
		||||
                '<pick-template :templates="this.templates" :preventDefaultMoveToGenerate="true" ' +
 | 
			
		||||
                    ':entityClass="faked" @go-to-generate-document="generateDoc"></pick-template>',
 | 
			
		||||
            components: {
 | 
			
		||||
                PickTemplate,
 | 
			
		||||
            },
 | 
			
		||||
            data() {
 | 
			
		||||
                return {
 | 
			
		||||
                    templates: templates,
 | 
			
		||||
                    entityId: el.dataset.entityId,
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            methods: {
 | 
			
		||||
                generateDoc({event, link, template}) {
 | 
			
		||||
                    console.log('generateDoc');
 | 
			
		||||
                    console.log('link', link);
 | 
			
		||||
                    console.log('template', template);
 | 
			
		||||
 | 
			
		||||
                    let hiddenInput = document.querySelector("input[data-template-id]");
 | 
			
		||||
 | 
			
		||||
                    if (hiddenInput === null) {
 | 
			
		||||
                        console.error('hidden input not found');
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    hiddenInput.value = template;
 | 
			
		||||
 | 
			
		||||
                    let form = document.querySelector('form[name="chill_activitybundle_activity"');
 | 
			
		||||
 | 
			
		||||
                    if (form === null) {
 | 
			
		||||
                        console.error('form not found');
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    form.submit();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        createApp(picker).use(i18nGendoc).mount(el);
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@
 | 
			
		||||
                    <div class="wl-col title"><h3>{{ 'Referrer'|trans }}</h3></div>
 | 
			
		||||
                    <div class="wl-col list">
 | 
			
		||||
                        <p class="wl-item">
 | 
			
		||||
                            {{ activity.user|chill_entity_render_string|capitalize }}
 | 
			
		||||
                            {{ activity.user|chill_entity_render_box }}
 | 
			
		||||
                        </p>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -89,9 +89,9 @@
 | 
			
		||||
 | 
			
		||||
{%- if edit_form.documents is defined -%}
 | 
			
		||||
    {{ form_row(edit_form.documents) }}
 | 
			
		||||
    <div data-docgen-template-picker="data-docgen-template-picker" data-entity-class="Chill\ActivityBundle\Entity\Activity" data-entity-id="{{ entity.id }}"></div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
<div data-docgen-template-picker="data-docgen-template-picker" data-entity-class="Chill\ActivityBundle\Entity\Activity" data-entity-id="{{ entity.id }}"></div>
 | 
			
		||||
 | 
			
		||||
{% set person_id = null %}
 | 
			
		||||
{% if entity.person %}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,12 +24,10 @@
 | 
			
		||||
        window.activity = {{ activity_json|json_encode|raw }};
 | 
			
		||||
    </script>
 | 
			
		||||
    {{ encore_entry_script_tags('vue_activity') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block css %}
 | 
			
		||||
    {{ parent() }}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_async_upload') }}
 | 
			
		||||
    {{ encore_entry_link_tags('vue_activity') }}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,11 +39,9 @@
 | 
			
		||||
        window.activity = {{ activity_json|json_encode|raw }};
 | 
			
		||||
    </script>
 | 
			
		||||
    {{ encore_entry_script_tags('vue_activity') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block css %}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_async_upload') }}
 | 
			
		||||
    {{ encore_entry_link_tags('vue_activity') }}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
                        <p class="date-label">{{ activity.date|format_date('short') }}</p>
 | 
			
		||||
                    {%- endif -%}
 | 
			
		||||
 | 
			
		||||
                    <span class="like-h3">{{ activity.type.name | localize_translatable_string }}</span>
 | 
			
		||||
                    <span class="like-h3">{{ activity.type.name|localize_translatable_string }}</span>
 | 
			
		||||
 | 
			
		||||
                    {% if activity.emergency %}
 | 
			
		||||
                        <span class="badge bg-danger rounded-pill fs-6">{{ 'Emergency'|trans|upper }}</span>
 | 
			
		||||
@@ -41,7 +41,7 @@
 | 
			
		||||
                        {% if activity.user and t.userVisible %}
 | 
			
		||||
                            <li>
 | 
			
		||||
                                <span class="item-key">{{ 'Referrer'|trans ~ ': ' }}</span>
 | 
			
		||||
                                <b>{{ activity.user.usernameCanonical }}</b>
 | 
			
		||||
                                <b>{{ activity.user|chill_entity_render_box}}</b>
 | 
			
		||||
                            </li>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,7 @@
 | 
			
		||||
 | 
			
		||||
{%- if form.documents is defined -%}
 | 
			
		||||
    {{ form_row(form.documents) }}
 | 
			
		||||
    <div data-docgen-template-picker="data-docgen-template-picker" data-entity-class="Chill\ActivityBundle\Entity\Activity" data-entity-id="{{ entity.id }}"></div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{%- if form.attendee is defined -%}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,6 @@
 | 
			
		||||
    {{ parent() }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_async_upload') }}
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
        window.addEventListener('DOMContentLoaded', function (e) {
 | 
			
		||||
            chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
 | 
			
		||||
            '{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
 | 
			
		||||
        });
 | 
			
		||||
        window.activity = {{ activity_json|json_encode|raw }};
 | 
			
		||||
        {% if default_location is not null %}window.default_location_id = {{ default_location.id }}{% endif %};
 | 
			
		||||
    </script>
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ use Chill\DocGeneratorBundle\Context\DocGeneratorContextWithPublicFormInterface;
 | 
			
		||||
use Chill\DocGeneratorBundle\Context\Exception\UnexpectedTypeException;
 | 
			
		||||
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
 | 
			
		||||
use Chill\DocGeneratorBundle\Service\Context\BaseContextData;
 | 
			
		||||
use Chill\DocStoreBundle\Entity\Document;
 | 
			
		||||
use Chill\DocStoreBundle\Entity\StoredObject;
 | 
			
		||||
use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
 | 
			
		||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
 | 
			
		||||
@@ -210,11 +209,8 @@ class ActivityContext implements
 | 
			
		||||
     */
 | 
			
		||||
    public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void
 | 
			
		||||
    {
 | 
			
		||||
        $doc = new StoredObject();
 | 
			
		||||
        // TODO push document to remote
 | 
			
		||||
        $entity->addDocument($storedObject);
 | 
			
		||||
 | 
			
		||||
        $this->em->persist($doc);
 | 
			
		||||
 | 
			
		||||
        $entity->addDocument($doc);
 | 
			
		||||
        $this->em->persist($storedObject);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -167,7 +167,6 @@ class AsideActivityCategory
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->parent = $parent;
 | 
			
		||||
        dump($this);
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,29 +16,17 @@ use Chill\TaskBundle\Templating\UI\CountNotificationTask;
 | 
			
		||||
use Knp\Menu\MenuItem;
 | 
			
		||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
 | 
			
		||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
 | 
			
		||||
use Symfony\Component\Translation\TranslatorInterface;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 | 
			
		||||
class UserMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var AuthorizationCheckerInterface
 | 
			
		||||
     */
 | 
			
		||||
    public $authorizationChecker;
 | 
			
		||||
    public AuthorizationCheckerInterface $authorizationChecker;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var CountNotificationTask
 | 
			
		||||
     */
 | 
			
		||||
    public $counter;
 | 
			
		||||
    public CountNotificationTask $counter;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TokenStorageInterface
 | 
			
		||||
     */
 | 
			
		||||
    public $tokenStorage;
 | 
			
		||||
    public TokenStorageInterface $tokenStorage;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TranslatorInterface
 | 
			
		||||
     */
 | 
			
		||||
    public $translator;
 | 
			
		||||
    public TranslatorInterface $translator;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        CountNotificationTask $counter,
 | 
			
		||||
 
 | 
			
		||||
@@ -97,8 +97,6 @@ class CalendarType extends AbstractType
 | 
			
		||||
                    return $res;
 | 
			
		||||
                },
 | 
			
		||||
                static function (?string $dateAsString): DateTimeImmutable {
 | 
			
		||||
                    dump($dateAsString);
 | 
			
		||||
 | 
			
		||||
                    return new DateTimeImmutable($dateAsString);
 | 
			
		||||
                }
 | 
			
		||||
            ));
 | 
			
		||||
 
 | 
			
		||||
@@ -14,14 +14,18 @@ namespace Chill\CalendarBundle\Menu;
 | 
			
		||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
			
		||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
 | 
			
		||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
 | 
			
		||||
use Knp\Menu\MenuItem;
 | 
			
		||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
 | 
			
		||||
use Symfony\Component\Security\Core\Security;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 | 
			
		||||
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    protected AuthorizationHelper $authorizationHelper;
 | 
			
		||||
 | 
			
		||||
    protected Security $security;
 | 
			
		||||
 | 
			
		||||
    protected TokenStorageInterface $tokenStorage;
 | 
			
		||||
 | 
			
		||||
    protected TranslatorInterface $translator;
 | 
			
		||||
@@ -29,11 +33,13 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        TokenStorageInterface $tokenStorage,
 | 
			
		||||
        AuthorizationHelper $authorizationHelper,
 | 
			
		||||
        TranslatorInterface $translator
 | 
			
		||||
        TranslatorInterface $translator,
 | 
			
		||||
        Security $security
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->translator = $translator;
 | 
			
		||||
        $this->authorizationHelper = $authorizationHelper;
 | 
			
		||||
        $this->tokenStorage = $tokenStorage;
 | 
			
		||||
        $this->security = $security;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildMenu($menuId, MenuItem $menu, array $parameters)
 | 
			
		||||
@@ -41,12 +47,14 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
        $period = $parameters['accompanyingCourse'];
 | 
			
		||||
 | 
			
		||||
        if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()) {
 | 
			
		||||
            $menu->addChild($this->translator->trans('Calendar'), [
 | 
			
		||||
                'route' => 'chill_calendar_calendar_list',
 | 
			
		||||
                'routeParameters' => [
 | 
			
		||||
                    'accompanying_period_id' => $period->getId(),
 | 
			
		||||
                ], ])
 | 
			
		||||
                ->setExtras(['order' => 35]);
 | 
			
		||||
            if ($this->security->isGranted(AccompanyingPeriodVoter::SEE, $period)) {
 | 
			
		||||
                $menu->addChild($this->translator->trans('Calendar'), [
 | 
			
		||||
                    'route' => 'chill_calendar_calendar_list',
 | 
			
		||||
                    'routeParameters' => [
 | 
			
		||||
                        'accompanying_period_id' => $period->getId(),
 | 
			
		||||
                    ], ])
 | 
			
		||||
                    ->setExtras(['order' => 35]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
 | 
			
		||||
const buildLink = function(templateId, entityId, entityClass) {
 | 
			
		||||
    const
 | 
			
		||||
        entityIdEncoded = encodeURI(entityId),
 | 
			
		||||
        returnPath = encodeURIComponent(window.location.pathname + window.location.search + window.location.hash),
 | 
			
		||||
        entityClassEncoded = encodeURI(entityClass),
 | 
			
		||||
        url = `/fr/doc/gen/generate/from/${templateId}/for/${entityClassEncoded}/${entityIdEncoded}?returnPath=${returnPath}`
 | 
			
		||||
    ;
 | 
			
		||||
    console.log('computed Url');
 | 
			
		||||
    return url;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export {buildLink};
 | 
			
		||||
@@ -20,8 +20,8 @@
 | 
			
		||||
                                    <option v-bind:value="t.id">{{ t.name.fr || 'Aucun nom défini' }}</option>
 | 
			
		||||
                                </template>
 | 
			
		||||
                            </select>
 | 
			
		||||
                            <button v-if="canGenerate" class="btn btn-update btn-sm change-icon" type="button" @click="generateDocument"><i class="fa fa-fw fa-cog"></i></button>
 | 
			
		||||
                            <button v-else class="btn btn-update btn-sm change-icon" type="button" disabled ><i class="fa fa-fw fa-cog"></i></button>
 | 
			
		||||
                            <a v-if="canGenerate" class="btn btn-update btn-sm change-icon" :href="buildUrlGenerate" @click.prevent="clickGenerate($event, buildUrlGenerate)"><i class="fa fa-fw fa-cog"></i></a>
 | 
			
		||||
                            <a v-else class="btn btn-update btn-sm change-icon" href="#" disabled ><i class="fa fa-fw fa-cog"></i></a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
@@ -39,24 +39,27 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
import {buildLink} from 'ChillDocGeneratorAssets/lib/document-generator';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "PickTemplate",
 | 
			
		||||
    props: {
 | 
			
		||||
        entityId: [String, Number],
 | 
			
		||||
        entityClass: {
 | 
			
		||||
            type: String,
 | 
			
		||||
            required: true,
 | 
			
		||||
            required: false,
 | 
			
		||||
        },
 | 
			
		||||
        templates: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            required: true,
 | 
			
		||||
        },
 | 
			
		||||
        // beforeMove execute "something" before
 | 
			
		||||
        beforeMove: {
 | 
			
		||||
            type: Function,
 | 
			
		||||
        preventDefaultMoveToGenerate: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: false,
 | 
			
		||||
            default: false,
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    emits: ['goToGenerateDocument'],
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            template: null,
 | 
			
		||||
@@ -74,66 +77,37 @@ export default {
 | 
			
		||||
            return true;
 | 
			
		||||
        },
 | 
			
		||||
        getDescription() {
 | 
			
		||||
            if (null === this.template) {
 | 
			
		||||
                return '';
 | 
			
		||||
            }
 | 
			
		||||
            let desc = this.templates.find(t => t.id === this.template);
 | 
			
		||||
            if (null === desc) {
 | 
			
		||||
                return '';
 | 
			
		||||
            }
 | 
			
		||||
            return desc.description || '';
 | 
			
		||||
        },
 | 
			
		||||
        buildUrlGenerate() {
 | 
			
		||||
            if (null === this.template) {
 | 
			
		||||
                return '#';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return buildLink(this.template, this.entityId, this.entityClass);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        generateDocument() {
 | 
			
		||||
            console.log('generateDocument');
 | 
			
		||||
            console.log('beforeMove', this.beforeMove);
 | 
			
		||||
            if (this.beforeMove != null) {
 | 
			
		||||
                console.log('execute before move');
 | 
			
		||||
                let r = this.beforeMove();
 | 
			
		||||
                if (r instanceof Promise) {
 | 
			
		||||
                    r.then((obj) => this.goToGenerate(obj));
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.goToGenerate();
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                this.goToGenerate();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        goToGenerate(obj) {
 | 
			
		||||
            console.log('goToGenerate');
 | 
			
		||||
            console.log('obj', obj);
 | 
			
		||||
            console.log('entityId', this.entityId);
 | 
			
		||||
            let
 | 
			
		||||
                realId = this.entityId,
 | 
			
		||||
                realEntityClass = this.entityClass
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
            if (obj !== undefined) {
 | 
			
		||||
                if (obj.entityId !== undefined) {
 | 
			
		||||
                    realId = obj.entityId;
 | 
			
		||||
                }
 | 
			
		||||
                if (obj.entityClass !== undefined) {
 | 
			
		||||
                    realEntityClass = obj.entityClass;
 | 
			
		||||
                }
 | 
			
		||||
        clickGenerate(event, link) {
 | 
			
		||||
            if (!this.preventDefaultMoveToGenerate) {
 | 
			
		||||
                window.location.assign(link);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            console.log('realId', realId);
 | 
			
		||||
            console.log('realEntityClass', realEntityClass);
 | 
			
		||||
 | 
			
		||||
            const
 | 
			
		||||
                entityId = encodeURI(realId),
 | 
			
		||||
                returnPath = encodeURIComponent(window.location.pathname + window.location.search + window.location.hash),
 | 
			
		||||
                fqdnEntityClass = encodeURI(realEntityClass),
 | 
			
		||||
                url = `/fr/doc/gen/generate/from/${this.template}/for/${fqdnEntityClass}/${entityId}?returnPath=${returnPath}`
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
            console.log('I will generate your doc at', url);
 | 
			
		||||
            window.location.assign(url);
 | 
			
		||||
            this.$emit('goToGenerateDocument', {event, link, template: this.template});
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    i18n: {
 | 
			
		||||
        messages: {
 | 
			
		||||
            fr: {
 | 
			
		||||
                generate_document: 'Générer un document',
 | 
			
		||||
                select_a_template: 'Choisir un gabarit',
 | 
			
		||||
                select_a_template: 'Choisir un modèle',
 | 
			
		||||
                choose_a_template: 'Choisir',
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,9 @@ namespace Chill\DocStoreBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
 | 
			
		||||
use Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType;
 | 
			
		||||
use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository;
 | 
			
		||||
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorFactory;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
			
		||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
 | 
			
		||||
use DateTime;
 | 
			
		||||
@@ -29,20 +31,15 @@ use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 */
 | 
			
		||||
class DocumentAccompanyingCourseController extends AbstractController
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var AuthorizationHelper
 | 
			
		||||
     */
 | 
			
		||||
    protected $authorizationHelper;
 | 
			
		||||
    protected AuthorizationHelper $authorizationHelper;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var EventDispatcherInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $eventDispatcher;
 | 
			
		||||
    protected EventDispatcherInterface $eventDispatcher;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TranslatorInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $translator;
 | 
			
		||||
    protected TranslatorInterface $translator;
 | 
			
		||||
 | 
			
		||||
    private AccompanyingCourseDocumentRepository $courseRepository;
 | 
			
		||||
 | 
			
		||||
    private PaginatorFactory $paginatorFactory;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * DocumentAccompanyingCourseController constructor.
 | 
			
		||||
@@ -50,11 +47,15 @@ class DocumentAccompanyingCourseController extends AbstractController
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        TranslatorInterface $translator,
 | 
			
		||||
        EventDispatcherInterface $eventDispatcher,
 | 
			
		||||
        AuthorizationHelper $authorizationHelper
 | 
			
		||||
        AuthorizationHelper $authorizationHelper,
 | 
			
		||||
        PaginatorFactory $paginatorFactory,
 | 
			
		||||
        AccompanyingCourseDocumentRepository $courseRepository
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->translator = $translator;
 | 
			
		||||
        $this->eventDispatcher = $eventDispatcher;
 | 
			
		||||
        $this->authorizationHelper = $authorizationHelper;
 | 
			
		||||
        $this->paginatorFactory = $paginatorFactory;
 | 
			
		||||
        $this->courseRepository = $courseRepository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -130,11 +131,15 @@ class DocumentAccompanyingCourseController extends AbstractController
 | 
			
		||||
 | 
			
		||||
        $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::SEE, $course);
 | 
			
		||||
 | 
			
		||||
        $documents = $em
 | 
			
		||||
            ->getRepository('ChillDocStoreBundle:AccompanyingCourseDocument')
 | 
			
		||||
        $total = $this->courseRepository->countByCourse($course);
 | 
			
		||||
        $pagination = $this->paginatorFactory->create($total);
 | 
			
		||||
 | 
			
		||||
        $documents = $this->courseRepository
 | 
			
		||||
            ->findBy(
 | 
			
		||||
                ['course' => $course],
 | 
			
		||||
                ['date' => 'DESC']
 | 
			
		||||
                ['date' => 'DESC'],
 | 
			
		||||
                $pagination->getItemsPerPage(),
 | 
			
		||||
                $pagination->getCurrentPageFirstItemNumber()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        return $this->render(
 | 
			
		||||
@@ -142,6 +147,7 @@ class DocumentAccompanyingCourseController extends AbstractController
 | 
			
		||||
            [
 | 
			
		||||
                'documents' => $documents,
 | 
			
		||||
                'accompanyingCourse' => $course,
 | 
			
		||||
                'pagination' => $pagination,
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,8 @@ namespace Chill\DocStoreBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Chill\DocStoreBundle\Entity\PersonDocument;
 | 
			
		||||
use Chill\DocStoreBundle\Form\PersonDocumentType;
 | 
			
		||||
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
 | 
			
		||||
use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorFactory;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Chill\PersonBundle\Privacy\PrivacyEvent;
 | 
			
		||||
@@ -24,7 +25,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
use Symfony\Component\Routing\Annotation\Route;
 | 
			
		||||
use Symfony\Component\Translation\TranslatorInterface;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class DocumentPersonController.
 | 
			
		||||
@@ -35,20 +36,15 @@ use Symfony\Component\Translation\TranslatorInterface;
 | 
			
		||||
 */
 | 
			
		||||
class DocumentPersonController extends AbstractController
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var AuthorizationHelper
 | 
			
		||||
     */
 | 
			
		||||
    protected $authorizationHelper;
 | 
			
		||||
    protected AuthorizationHelper $authorizationHelper;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var EventDispatcherInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $eventDispatcher;
 | 
			
		||||
    protected EventDispatcherInterface $eventDispatcher;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TranslatorInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $translator;
 | 
			
		||||
    protected TranslatorInterface $translator;
 | 
			
		||||
 | 
			
		||||
    private PaginatorFactory $paginatorFactory;
 | 
			
		||||
 | 
			
		||||
    private PersonDocumentACLAwareRepositoryInterface $personDocumentACLAwareRepository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * DocumentPersonController constructor.
 | 
			
		||||
@@ -56,11 +52,15 @@ class DocumentPersonController extends AbstractController
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        TranslatorInterface $translator,
 | 
			
		||||
        EventDispatcherInterface $eventDispatcher,
 | 
			
		||||
        AuthorizationHelper $authorizationHelper
 | 
			
		||||
        AuthorizationHelper $authorizationHelper,
 | 
			
		||||
        PaginatorFactory $paginatorFactory,
 | 
			
		||||
        PersonDocumentACLAwareRepositoryInterface $personDocumentACLAwareRepository
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->translator = $translator;
 | 
			
		||||
        $this->eventDispatcher = $eventDispatcher;
 | 
			
		||||
        $this->authorizationHelper = $authorizationHelper;
 | 
			
		||||
        $this->paginatorFactory = $paginatorFactory;
 | 
			
		||||
        $this->personDocumentACLAwareRepository = $personDocumentACLAwareRepository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -156,19 +156,15 @@ class DocumentPersonController extends AbstractController
 | 
			
		||||
 | 
			
		||||
        $this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
 | 
			
		||||
 | 
			
		||||
        $reachableScopes = $this->authorizationHelper
 | 
			
		||||
            ->getReachableScopes(
 | 
			
		||||
                $this->getUser(),
 | 
			
		||||
                PersonDocumentVoter::SEE,
 | 
			
		||||
                $person->getCenter()
 | 
			
		||||
            );
 | 
			
		||||
        $total = $this->personDocumentACLAwareRepository->countByPerson($person);
 | 
			
		||||
        $pagination = $this->paginatorFactory->create($total);
 | 
			
		||||
 | 
			
		||||
        $documents = $em
 | 
			
		||||
            ->getRepository('ChillDocStoreBundle:PersonDocument')
 | 
			
		||||
            ->findBy(
 | 
			
		||||
                ['person' => $person, 'scope' => $reachableScopes],
 | 
			
		||||
                ['date' => 'DESC']
 | 
			
		||||
            );
 | 
			
		||||
        $documents = $this->personDocumentACLAwareRepository->findByPerson(
 | 
			
		||||
            $person,
 | 
			
		||||
            [],
 | 
			
		||||
            $pagination->getItemsPerPage(),
 | 
			
		||||
            $pagination->getCurrentPageFirstItemNumber()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $event = new PrivacyEvent($person, [
 | 
			
		||||
            'element_class' => PersonDocument::class,
 | 
			
		||||
@@ -181,6 +177,7 @@ class DocumentPersonController extends AbstractController
 | 
			
		||||
            [
 | 
			
		||||
                'documents' => $documents,
 | 
			
		||||
                'person' => $person,
 | 
			
		||||
                'pagination' => $pagination,
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf
 | 
			
		||||
        $loader->load('services/menu.yaml');
 | 
			
		||||
        $loader->load('services/fixtures.yaml');
 | 
			
		||||
        $loader->load('services/form.yaml');
 | 
			
		||||
        $loader->load('services/templating.yaml');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function prepend(ContainerBuilder $container)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,13 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\DocStoreBundle\Entity;
 | 
			
		||||
 | 
			
		||||
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
 | 
			
		||||
use Chill\MainBundle\Entity\HasScopeInterface;
 | 
			
		||||
use Chill\MainBundle\Entity\Scope;
 | 
			
		||||
use Chill\MainBundle\Entity\User;
 | 
			
		||||
use DateTimeInterface;
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
@@ -20,8 +26,12 @@ use Symfony\Component\Validator\Constraints as Assert;
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\MappedSuperclass
 | 
			
		||||
 */
 | 
			
		||||
class Document implements HasScopeInterface
 | 
			
		||||
class Document implements HasScopeInterface, TrackCreationInterface, TrackUpdateInterface
 | 
			
		||||
{
 | 
			
		||||
    use TrackCreationTrait;
 | 
			
		||||
 | 
			
		||||
    use TrackUpdateTrait;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\ManyToOne(targetEntity="Chill\DocStoreBundle\Entity\DocumentCategory")
 | 
			
		||||
     * @ORM\JoinColumns({
 | 
			
		||||
@@ -67,6 +77,11 @@ class Document implements HasScopeInterface
 | 
			
		||||
     */
 | 
			
		||||
    private $scope;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\ManyToOne(targetEntity="Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate")
 | 
			
		||||
     */
 | 
			
		||||
    private $template;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="text")
 | 
			
		||||
     * @Assert\Length(
 | 
			
		||||
@@ -82,9 +97,6 @@ class Document implements HasScopeInterface
 | 
			
		||||
     */
 | 
			
		||||
    private $user;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return DocumentCategory
 | 
			
		||||
     */
 | 
			
		||||
    public function getCategory(): ?DocumentCategory
 | 
			
		||||
    {
 | 
			
		||||
        return $this->category;
 | 
			
		||||
@@ -115,11 +127,16 @@ class Document implements HasScopeInterface
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Chill\MainBundle\Entity\Scope
 | 
			
		||||
     */
 | 
			
		||||
    public function getScope()
 | 
			
		||||
    public function getScope(): ?Scope
 | 
			
		||||
    {
 | 
			
		||||
        return $this->scope;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getTemplate(): ?DocGeneratorTemplate
 | 
			
		||||
    {
 | 
			
		||||
        return $this->template;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getTitle(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->title;
 | 
			
		||||
@@ -165,6 +182,13 @@ class Document implements HasScopeInterface
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setTemplate(?DocGeneratorTemplate $template): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->template = $template;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setTitle(string $title): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->title = $title;
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,12 @@ use Chill\MainBundle\Form\Type\ChillDateType;
 | 
			
		||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
 | 
			
		||||
use Chill\MainBundle\Form\Type\ScopePickerType;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
			
		||||
use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher;
 | 
			
		||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
 | 
			
		||||
use Doctrine\ORM\EntityRepository;
 | 
			
		||||
use Doctrine\Persistence\ObjectManager;
 | 
			
		||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
 | 
			
		||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
 | 
			
		||||
use Symfony\Component\Form\AbstractType;
 | 
			
		||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
 | 
			
		||||
use Symfony\Component\Form\FormBuilderInterface;
 | 
			
		||||
@@ -51,14 +53,25 @@ class PersonDocumentType extends AbstractType
 | 
			
		||||
     */
 | 
			
		||||
    protected $user;
 | 
			
		||||
 | 
			
		||||
    private ParameterBagInterface $parameterBag;
 | 
			
		||||
 | 
			
		||||
    private ScopeResolverDispatcher $scopeResolverDispatcher;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        TranslatableStringHelper $translatableStringHelper
 | 
			
		||||
        TranslatableStringHelper $translatableStringHelper,
 | 
			
		||||
        ScopeResolverDispatcher $scopeResolverDispatcher,
 | 
			
		||||
        ParameterBagInterface $parameterBag
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->translatableStringHelper = $translatableStringHelper;
 | 
			
		||||
        $this->scopeResolverDispatcher = $scopeResolverDispatcher;
 | 
			
		||||
        $this->parameterBag = $parameterBag;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildForm(FormBuilderInterface $builder, array $options)
 | 
			
		||||
    {
 | 
			
		||||
        $document = $options['data'];
 | 
			
		||||
        $isScopeConcerned = $this->scopeResolverDispatcher->isConcerned($document);
 | 
			
		||||
 | 
			
		||||
        $builder
 | 
			
		||||
            ->add('title', TextType::class)
 | 
			
		||||
            ->add('description', ChillTextareaType::class, [
 | 
			
		||||
@@ -67,10 +80,6 @@ class PersonDocumentType extends AbstractType
 | 
			
		||||
            ->add('object', StoredObjectType::class, [
 | 
			
		||||
                'error_bubbling' => true,
 | 
			
		||||
            ])
 | 
			
		||||
            ->add('scope', ScopePickerType::class, [
 | 
			
		||||
                'center' => $options['center'],
 | 
			
		||||
                'role' => $options['role'],
 | 
			
		||||
            ])
 | 
			
		||||
            ->add('date', ChillDateType::class)
 | 
			
		||||
            ->add('category', EntityType::class, [
 | 
			
		||||
                'placeholder' => 'Choose a document category',
 | 
			
		||||
@@ -84,6 +93,13 @@ class PersonDocumentType extends AbstractType
 | 
			
		||||
                    return $entity ? $this->translatableStringHelper->localize($entity->getName()) : '';
 | 
			
		||||
                },
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
        if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) {
 | 
			
		||||
            $builder->add('scope', ScopePickerType::class, [
 | 
			
		||||
                'center' => $options['center'],
 | 
			
		||||
                'role' => $options['role'],
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function configureOptions(OptionsResolver $resolver)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
<?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\DocStoreBundle\Repository;
 | 
			
		||||
 | 
			
		||||
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
 | 
			
		||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
 | 
			
		||||
use Doctrine\ORM\EntityManagerInterface;
 | 
			
		||||
use Doctrine\ORM\EntityRepository;
 | 
			
		||||
use Doctrine\ORM\QueryBuilder;
 | 
			
		||||
use Doctrine\Persistence\ObjectRepository;
 | 
			
		||||
 | 
			
		||||
class AccompanyingCourseDocumentRepository implements ObjectRepository
 | 
			
		||||
{
 | 
			
		||||
    private EntityManagerInterface $em;
 | 
			
		||||
 | 
			
		||||
    private EntityRepository $repository;
 | 
			
		||||
 | 
			
		||||
    public function __construct(EntityManagerInterface $em)
 | 
			
		||||
    {
 | 
			
		||||
        $this->em = $em;
 | 
			
		||||
        $this->repository = $em->getRepository(AccompanyingCourseDocument::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildQueryByCourse(AccompanyingPeriod $course): QueryBuilder
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->repository->createQueryBuilder('d');
 | 
			
		||||
 | 
			
		||||
        $qb
 | 
			
		||||
            ->where($qb->expr()->eq('d.course', ':course'))
 | 
			
		||||
            ->setParameter('course', $course);
 | 
			
		||||
 | 
			
		||||
        return $qb;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function countByCourse(AccompanyingPeriod $course): int
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->buildQueryByCourse($course)->select('COUNT(d)');
 | 
			
		||||
 | 
			
		||||
        return $qb->getQuery()->getSingleScalarResult();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function find($id): ?AccompanyingCourseDocument
 | 
			
		||||
    {
 | 
			
		||||
        return $this->repository->find($id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findAll(): array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->repository->findAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findOneBy(array $criteria): ?AccompanyingCourseDocument
 | 
			
		||||
    {
 | 
			
		||||
        return $this->findOneBy($criteria);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getClassName()
 | 
			
		||||
    {
 | 
			
		||||
        return AccompanyingCourseDocument::class;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
<?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\DocStoreBundle\Repository;
 | 
			
		||||
 | 
			
		||||
use Chill\DocStoreBundle\Entity\PersonDocument;
 | 
			
		||||
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
 | 
			
		||||
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Doctrine\ORM\EntityManagerInterface;
 | 
			
		||||
use Doctrine\ORM\QueryBuilder;
 | 
			
		||||
use Symfony\Component\Security\Core\Security;
 | 
			
		||||
 | 
			
		||||
class PersonDocumentACLAwareRepository implements PersonDocumentACLAwareRepositoryInterface
 | 
			
		||||
{
 | 
			
		||||
    private AuthorizationHelperInterface $authorizationHelper;
 | 
			
		||||
 | 
			
		||||
    private CenterResolverDispatcher $centerResolverDispatcher;
 | 
			
		||||
 | 
			
		||||
    private EntityManagerInterface $em;
 | 
			
		||||
 | 
			
		||||
    private Security $security;
 | 
			
		||||
 | 
			
		||||
    public function __construct(EntityManagerInterface $em, AuthorizationHelperInterface $authorizationHelper, CenterResolverDispatcher $centerResolverDispatcher, Security $security)
 | 
			
		||||
    {
 | 
			
		||||
        $this->em = $em;
 | 
			
		||||
        $this->authorizationHelper = $authorizationHelper;
 | 
			
		||||
        $this->centerResolverDispatcher = $centerResolverDispatcher;
 | 
			
		||||
        $this->security = $security;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildQueryByPerson(Person $person): QueryBuilder
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->em->getRepository(PersonDocument::class)->createQueryBuilder('d');
 | 
			
		||||
 | 
			
		||||
        $qb
 | 
			
		||||
            ->where($qb->expr()->eq('d.person', ':person'))
 | 
			
		||||
            ->setParameter('person', $person);
 | 
			
		||||
 | 
			
		||||
        return $qb;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function countByPerson(Person $person): int
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->buildQueryByPerson($person)->select('COUNT(d)');
 | 
			
		||||
 | 
			
		||||
        $this->addACL($qb, $person);
 | 
			
		||||
 | 
			
		||||
        return $qb->getQuery()->getSingleScalarResult();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findByPerson(Person $person, array $orderBy = [], int $limit = 20, int $offset = 0): array
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->buildQueryByPerson($person)->select('d');
 | 
			
		||||
 | 
			
		||||
        $this->addACL($qb, $person);
 | 
			
		||||
 | 
			
		||||
        foreach ($orderBy as [$field, $order]) {
 | 
			
		||||
            $qb->addOrderBy($field, $order);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $qb->setFirstResult($offset)->setMaxResults($limit);
 | 
			
		||||
 | 
			
		||||
        return $qb->getQuery()->getResult();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function addACL(QueryBuilder $qb, Person $person): void
 | 
			
		||||
    {
 | 
			
		||||
        $center = $this->centerResolverDispatcher->resolveCenter($person);
 | 
			
		||||
 | 
			
		||||
        $reachableScopes = $this->authorizationHelper
 | 
			
		||||
            ->getReachableScopes(
 | 
			
		||||
                $this->security->getUser(),
 | 
			
		||||
                PersonDocumentVoter::SEE,
 | 
			
		||||
                $center
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        $qb->andWhere($qb->expr()->in('d.scope', ':scopes'))
 | 
			
		||||
            ->setParameter('scopes', $reachableScopes);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
<?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\DocStoreBundle\Repository;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
 | 
			
		||||
interface PersonDocumentACLAwareRepositoryInterface
 | 
			
		||||
{
 | 
			
		||||
    public function countByPerson(Person $person): int;
 | 
			
		||||
 | 
			
		||||
    public function findByPerson(Person $person, array $orderBy = [], int $limit = 20, int $offset = 0): array;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
 | 
			
		||||
 | 
			
		||||
<div class="flex-table accompanying_course_work-list">
 | 
			
		||||
    <div class="item-bloc document-item bg-chill-llight-gray">
 | 
			
		||||
@@ -8,14 +9,15 @@
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-8">
 | 
			
		||||
                <h3>{{ document.title }}</h3>
 | 
			
		||||
                <small>{{ document.object.type }}</small>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
                {{ mm.mimeIcon(document.object.type) }}
 | 
			
		||||
 | 
			
		||||
                {% if document.description is not empty %}
 | 
			
		||||
                    <blockquote class="chill-user-quote mt-2">
 | 
			
		||||
                    <blockquote class="chill-user-quote mt-4">
 | 
			
		||||
                        {{ document.description }}
 | 
			
		||||
                    </blockquote>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@@ -32,30 +34,31 @@
 | 
			
		||||
 | 
			
		||||
{% if display_action is defined and display_action == true %}
 | 
			
		||||
    <ul class="record_actions">
 | 
			
		||||
        {% if document.course != null and is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', document.course) %}
 | 
			
		||||
            <li>
 | 
			
		||||
                <a href="{{ path('chill_person_accompanying_course_index', {'accompanying_period_id': document.course.id}) }}" class="btn btn-show change-icon">
 | 
			
		||||
                    <i class="fa fa-random"></i> {{ 'Course number'|trans }} {{ document.course.id }}
 | 
			
		||||
                </a>
 | 
			
		||||
            </li>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        <li>
 | 
			
		||||
            {{ m.download_button(document.object, document.title) }}
 | 
			
		||||
        </li>
 | 
			
		||||
        <li>
 | 
			
		||||
        {% if not freezed %}
 | 
			
		||||
            {% set button = {
 | 
			
		||||
                'changeIcon': 'fa-unlock',
 | 
			
		||||
            } %}{#
 | 
			
		||||
                'changeClass'   string
 | 
			
		||||
                'noText'        boolean
 | 
			
		||||
            #}
 | 
			
		||||
            {# vue component #}
 | 
			
		||||
            <span
 | 
			
		||||
                data-module="wopi-link"
 | 
			
		||||
                data-wopi-url="{{ path('chill_wopi_file_edit', {'fileId': document.object.uuid}) }}"
 | 
			
		||||
                data-doc-title="{{ document.title|e('html_attr') }}"
 | 
			
		||||
                data-doc-type="{{ document.object.type|e('html_attr') }}"
 | 
			
		||||
                data-button="{{ button|json_encode }}"
 | 
			
		||||
            ></span>
 | 
			
		||||
        {% else %}
 | 
			
		||||
            <a class="btn btn-update change-icon disabled" href="#" title="{{ 'workflow.freezed document'|trans }}">
 | 
			
		||||
                <i class="fa fa-lock me-2"></i>{{ 'Update document'|trans }}
 | 
			
		||||
            </a>
 | 
			
		||||
        {% if chill_document_is_editable(document.object) %}
 | 
			
		||||
            {% if not freezed %}
 | 
			
		||||
                {{ document.object|chill_document_edit_button({'title': document.title|e('html') }) }}
 | 
			
		||||
            {% else %}
 | 
			
		||||
                <a class="btn btn-wopilink disabled" href="#" title="{{ 'workflow.freezed document'|trans }}">
 | 
			
		||||
                    {{ 'Update document'|trans }}
 | 
			
		||||
                </a>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE', document) and document.course != null %}
 | 
			
		||||
            <li>
 | 
			
		||||
                <a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': document.course.id, 'id': document.id}) }}" class="btn btn-show"></a>
 | 
			
		||||
            </li>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
	{{ form_row(form.description) }}
 | 
			
		||||
	{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
 | 
			
		||||
 | 
			
		||||
	<ul class="record_actions">
 | 
			
		||||
	<ul class="record_actions sticky-form-buttons">
 | 
			
		||||
		<li class="cancel">
 | 
			
		||||
			<a href="{{ path('accompanying_course_document_index', {'course': accompanyingCourse.id}) }}" class="btn btn-cancel">
 | 
			
		||||
				{{ 'Back to the list' | trans }}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,6 @@
 | 
			
		||||
 | 
			
		||||
{% set activeRouteKey = '' %}
 | 
			
		||||
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
 | 
			
		||||
 | 
			
		||||
{% block title %}
 | 
			
		||||
	{{ 'Documents' }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@@ -11,64 +9,35 @@
 | 
			
		||||
{% block js %}
 | 
			
		||||
	{{ parent() }}
 | 
			
		||||
	{{ encore_entry_script_tags('mod_async_upload') }}
 | 
			
		||||
  {{ encore_entry_script_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block css %}
 | 
			
		||||
	{{ parent() }}
 | 
			
		||||
	{{ encore_entry_link_tags('mod_async_upload') }}
 | 
			
		||||
  {{ encore_entry_link_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
    {{ encore_entry_link_tags('mod_docgen_picktemplate') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="col-md-10 col-xxl">
 | 
			
		||||
	<h1>{{ 'Documents' }}</h1>
 | 
			
		||||
 | 
			
		||||
	<table class="table table-bordered border-dark table-striped">
 | 
			
		||||
 | 
			
		||||
		<thead>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<th>{{ 'Title' | trans }}</th>
 | 
			
		||||
				<th>{{ 'Category'|trans }}</th>
 | 
			
		||||
				<th>{{ 'Actions' | trans }}</th>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</thead>
 | 
			
		||||
		<tbody>
 | 
			
		||||
	{% if documents|length == 0 %}
 | 
			
		||||
            <p class="chill-no-data-statement">{{ 'No documents'|trans }}</p>
 | 
			
		||||
    {% else %}
 | 
			
		||||
		<div class="flex-table chill-task-list">
 | 
			
		||||
			{% for document in documents %}
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td>{{ document.title }}</td>
 | 
			
		||||
					<td>{% if document.category %}{{ document.category.name|localize_translatable_string }}{% endif %}</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<ul class="record_actions">
 | 
			
		||||
							{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
 | 
			
		||||
								<li>
 | 
			
		||||
									{{ m.download_button(document.object, document.title) }}
 | 
			
		||||
								</li>
 | 
			
		||||
								<li>
 | 
			
		||||
									<a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a>
 | 
			
		||||
								</li>
 | 
			
		||||
							{% endif %}
 | 
			
		||||
							{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
 | 
			
		||||
								<li>
 | 
			
		||||
									<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
 | 
			
		||||
								</li>
 | 
			
		||||
							{% endif %}
 | 
			
		||||
						</ul>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
			{% else %}
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td colspan="9" style="text-align:center;">
 | 
			
		||||
						<span class="chill-no-data-statement">{{ 'Any document found'|trans }}</span>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
				{% include 'ChillDocStoreBundle:List:list_item.html.twig' %}
 | 
			
		||||
			{% endfor %}
 | 
			
		||||
		</tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
		</div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    <div data-docgen-template-picker="data-docgen-template-picker" data-entity-class="Chill\PersonBundle\Entity\AccompanyingPeriod" data-entity-id="{{ accompanyingCourse.id }}"></div>
 | 
			
		||||
	{{ chill_pagination(pagination) }}
 | 
			
		||||
 | 
			
		||||
	<div data-docgen-template-picker="data-docgen-template-picker" data-entity-class="Chill\PersonBundle\Entity\AccompanyingPeriod" data-entity-id="{{ accompanyingCourse.id }}"></div>
 | 
			
		||||
 | 
			
		||||
	{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', accompanyingCourse) %}
 | 
			
		||||
		<ul class="record_actions">
 | 
			
		||||
		<ul class="record_actions sticky-form-buttons">
 | 
			
		||||
			<li class="create">
 | 
			
		||||
				<a href="{{ path('accompanying_course_document_new', {'course': accompanyingCourse.id}) }}" class="btn btn-create">
 | 
			
		||||
					{{ 'Create'|trans }}
 | 
			
		||||
@@ -76,4 +45,6 @@
 | 
			
		||||
			</li>
 | 
			
		||||
		</ul>
 | 
			
		||||
	{% endif %}
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
{% set activeRouteKey = '' %}
 | 
			
		||||
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
 | 
			
		||||
 | 
			
		||||
{% block title %}
 | 
			
		||||
	{# {{ 'Detail of document of %name%'|trans({ '%name%': accompanyingCourse|chill_entity_render_string } ) }} #}
 | 
			
		||||
@@ -18,16 +19,18 @@
 | 
			
		||||
{% block content %}
 | 
			
		||||
<div class="document-show">
 | 
			
		||||
    <h1>{{ block('title') }}</h1>
 | 
			
		||||
    
 | 
			
		||||
    <dl class="chill_view_data">
 | 
			
		||||
 | 
			
		||||
    {{ mm.mimeIcon(document.object.type) }}
 | 
			
		||||
 | 
			
		||||
    <dl class="chill_view_data mt-4">
 | 
			
		||||
        <dt>{{ 'Title'|trans }}</dt>
 | 
			
		||||
        <dd>{{ document.title }}</dd>
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        {% if document.category is not null %}
 | 
			
		||||
            <dt>{{ 'Category'|trans }}</dt>
 | 
			
		||||
            <dd>{{ document.category.name|localize_translatable_string }}</dd>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        <dt>{{ 'Description' | trans }}</dt>
 | 
			
		||||
        <dd>
 | 
			
		||||
            {% if document.description is empty %}
 | 
			
		||||
@@ -39,7 +42,7 @@
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </dd>
 | 
			
		||||
    </dl>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    <ul class="record_actions sticky-form-buttons">
 | 
			
		||||
        <li class="cancel">
 | 
			
		||||
            <a href="{{ path('accompanying_course_document_index', {'course': accompanyingCourse.id}) }}" class="btn btn-cancel">
 | 
			
		||||
@@ -49,11 +52,15 @@
 | 
			
		||||
        <li>
 | 
			
		||||
            {{ m.download_button(document.object, document.title) }}
 | 
			
		||||
        </li>
 | 
			
		||||
        {% if chill_document_is_editable(document.object) %}
 | 
			
		||||
            <li>
 | 
			
		||||
                {{ document.object|chill_document_edit_button }}
 | 
			
		||||
            </li>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
 | 
			
		||||
            <li>
 | 
			
		||||
                <a href="{{ path('accompanying_course_document_edit', {'id': document.id, 'course': accompanyingCourse.id}) }}" class="btn btn-edit">
 | 
			
		||||
                    {{ 'Edit' | trans }}
 | 
			
		||||
                </a>
 | 
			
		||||
                <a href="{{ path('accompanying_course_document_edit', {'id': document.id, 'course': accompanyingCourse.id}) }}"
 | 
			
		||||
                   class="btn btn-edit" title="{{ 'Edit attributes' | trans }}"></a>
 | 
			
		||||
            </li>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {% set workflows_frame = chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) %}
 | 
			
		||||
@@ -65,7 +72,7 @@
 | 
			
		||||
    </ul>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
{% block block_post_menu %}
 | 
			
		||||
    <div class="post-menu pt-4"></div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@@ -74,4 +81,4 @@
 | 
			
		||||
    {{ parent() }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_async_upload') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_entity_workflow_pick') }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
 | 
			
		||||
{# Twig way
 | 
			
		||||
    TODO: une route, un template avec un header CHILL et un iframe
 | 
			
		||||
#}
 | 
			
		||||
<a href="{{ chill_path_add_return_path('chill_wopi_file_edit', {'fileId': document.uuid}) }}"
 | 
			
		||||
    class="btn btn-wopilink">
 | 
			
		||||
    {{ 'online_edit_document'|trans }}
 | 
			
		||||
</a>
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
 | 
			
		||||
<div class="item-bloc">
 | 
			
		||||
    <div class="item-row">
 | 
			
		||||
        <div class="item-col">
 | 
			
		||||
            <div class="denomination h2">
 | 
			
		||||
                {{ document.title }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                {{ mm.mimeIcon(document.object.type) }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                <p>{{ document.category.name|localize_translatable_string }}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            {% if document.template is not null %}
 | 
			
		||||
                <div>
 | 
			
		||||
                    <p>{{ document.template.name.fr }}</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="item-col">
 | 
			
		||||
            <div class="container">
 | 
			
		||||
                {% if document.date is not null %}
 | 
			
		||||
                    <div class="dates row" style="float: right;">
 | 
			
		||||
                        <span>{{ document.createdAt|format_date('short') }}</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% if document.description is not empty %}
 | 
			
		||||
        <div class="item-row separator">
 | 
			
		||||
            <blockquote class="chill-user-quote">
 | 
			
		||||
                {{ document.description|chill_markdown_to_html }}
 | 
			
		||||
            </blockquote>
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    <div class="item-row separator">
 | 
			
		||||
        <div class="item-col item-meta">
 | 
			
		||||
            <div class="updatedBy">
 | 
			
		||||
                {{ 'Created by'|trans }}:
 | 
			
		||||
                <span class="user">{{ document.createdBy|chill_entity_render_string }}</span>
 | 
			
		||||
                <span class="date">le {{ document.createdAt|format_date('long') }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div>
 | 
			
		||||
    {% if document.course is defined %}
 | 
			
		||||
        <ul class="record_actions">
 | 
			
		||||
            {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
 | 
			
		||||
                <li>
 | 
			
		||||
                    {{ m.download_button(document.object, document.title) }}
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a>
 | 
			
		||||
                </li>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
 | 
			
		||||
                </li>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </ul>
 | 
			
		||||
    {% else %}
 | 
			
		||||
        <ul class="record_actions">
 | 
			
		||||
            {% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
 | 
			
		||||
                <li>
 | 
			
		||||
                    {{ m.download_button(document.object, document.title) }}
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
 | 
			
		||||
                </li>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            {% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
 | 
			
		||||
                </li>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </ul>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
{% macro mimeIcon(type) %}
 | 
			
		||||
    
 | 
			
		||||
    {# mapping
 | 
			
		||||
        forkawesome and mime type  https://gist.github.com/colemanw/9c9a12aae16a4bfe2678de86b661d922
 | 
			
		||||
    #}
 | 
			
		||||
    {% set mapmime = {
 | 
			
		||||
        'image': 'fa-file-image-o',
 | 
			
		||||
        'audio': 'fa-file-audio-o',
 | 
			
		||||
        'video': 'fa-file-video-o',
 | 
			
		||||
        'application/pdf': 'fa-file-pdf-o',
 | 
			
		||||
        'application/msword': 'fa-file-word-o',
 | 
			
		||||
        'application/vnd.ms-word': 'fa-file-word-o',
 | 
			
		||||
        'application/vnd.oasis.opendocument.text': 'fa-file-word-o',
 | 
			
		||||
        'application/vnd.openxmlformats-officedocument.wordprocessingml': 'fa-file-word-o',
 | 
			
		||||
        'application/vnd.ms-excel': 'fa-file-excel-o',
 | 
			
		||||
        'application/vnd.openxmlformats-officedocument.spreadsheetml': 'fa-file-excel-o',
 | 
			
		||||
        'application/vnd.oasis.opendocument.spreadsheet': 'fa-file-excel-o',
 | 
			
		||||
        'application/vnd.ms-powerpoint': 'fa-file-powerpoint-o',
 | 
			
		||||
        'application/vnd.openxmlformats-officedocument.presentationml': 'fa-file-powerpoint-o',
 | 
			
		||||
        'application/vnd.oasis.opendocument.presentation': 'fa-file-powerpoint-o',
 | 
			
		||||
        'text/plain': 'fa-file-text-o',
 | 
			
		||||
        'text/html': 'fa-file-code-o',
 | 
			
		||||
        'application/json': 'fa-file-code-o',
 | 
			
		||||
        'application/gzip': 'fa-file-archive-o',
 | 
			
		||||
        'application/zip': 'fa-file-archive-o',
 | 
			
		||||
    } %}
 | 
			
		||||
    
 | 
			
		||||
    {% set icon = 'fa-file-o' %}
 | 
			
		||||
    {% for key,val in mapmime %}
 | 
			
		||||
        {% if type starts with key %}
 | 
			
		||||
            {% set icon = val %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    
 | 
			
		||||
    {# TODO improve mapping
 | 
			
		||||
        mime type and friendly name  https://gist.github.com/rosskmurphy/3724501
 | 
			
		||||
    #}
 | 
			
		||||
    {% set maptype = {
 | 
			
		||||
        'fa-file-word-o': 'office document/texte',
 | 
			
		||||
        'fa-file-excel-o': 'office document/tableur',
 | 
			
		||||
        'fa-file-powerpoint-o': 'office document/presentation',
 | 
			
		||||
    } %}
 | 
			
		||||
    
 | 
			
		||||
    {% set label = type %}
 | 
			
		||||
    {% for key, val in maptype %}
 | 
			
		||||
        {% if icon == key %}
 | 
			
		||||
            {% set label = val %}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    
 | 
			
		||||
    <div class="metadata">
 | 
			
		||||
        <i class="fa {{ icon }} fa-lg me-1"></i>
 | 
			
		||||
        {{ label|capitalize }}
 | 
			
		||||
    </div>
 | 
			
		||||
{% endmacro %}
 | 
			
		||||
@@ -30,7 +30,9 @@
 | 
			
		||||
    {{ form_row(form.title) }}
 | 
			
		||||
    {{ form_row(form.date) }}
 | 
			
		||||
    {{ form_row(form.category) }}
 | 
			
		||||
    {{ form_row(form.scope) }}
 | 
			
		||||
    {% if form.scope is defined %}
 | 
			
		||||
        {{ form_row(form.scope) }}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {{ form_row(form.description) }}
 | 
			
		||||
    {{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,54 +30,24 @@
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block personcontent %}
 | 
			
		||||
 | 
			
		||||
<div class="col-md-10 col-xxl">
 | 
			
		||||
	<h1>{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}</h1>
 | 
			
		||||
 | 
			
		||||
	<table class="table table-bordered border-dark table-striped">
 | 
			
		||||
 | 
			
		||||
		<thead>
 | 
			
		||||
			<tr>
 | 
			
		||||
				<th>{{ 'Title' | trans }}</th>
 | 
			
		||||
				<th>{{ 'Category'|trans }}</th>
 | 
			
		||||
				<th>{{ 'Circle' | trans }}</th>
 | 
			
		||||
				<th>{{ 'Actions' | trans }}</th>
 | 
			
		||||
			</tr>
 | 
			
		||||
		</thead>
 | 
			
		||||
		<tbody>
 | 
			
		||||
	{% if documents|length == 0 %}
 | 
			
		||||
            <p class="chill-no-data-statement">{{ 'No documents'|trans }}</p>
 | 
			
		||||
    {% else %}
 | 
			
		||||
		<div class="flex-table chill-task-list">
 | 
			
		||||
			{% for document in documents %}
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td>{{ document.title }}</td>
 | 
			
		||||
					<td>{{ document.category.name|localize_translatable_string }}</td>
 | 
			
		||||
					<td>{{ document.scope.name|localize_translatable_string }}</td>
 | 
			
		||||
					<td>
 | 
			
		||||
						<ul class="record_actions">
 | 
			
		||||
							{% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
 | 
			
		||||
								<li>
 | 
			
		||||
									{{ m.download_button(document.object, document.title) }}
 | 
			
		||||
								</li>
 | 
			
		||||
								<li>
 | 
			
		||||
									<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
 | 
			
		||||
								</li>
 | 
			
		||||
							{% endif %}
 | 
			
		||||
							{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
 | 
			
		||||
								<li>
 | 
			
		||||
									<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
 | 
			
		||||
								</li>
 | 
			
		||||
							{% endif %}
 | 
			
		||||
						</ul>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
			{% else %}
 | 
			
		||||
				<tr>
 | 
			
		||||
					<td colspan="9" style="text-align:center;">
 | 
			
		||||
						<span class="chill-no-data-statement">{{ 'Any document found'|trans }}</span>
 | 
			
		||||
					</td>
 | 
			
		||||
				</tr>
 | 
			
		||||
				{% include 'ChillDocStoreBundle:List:list_item.html.twig' %}
 | 
			
		||||
			{% endfor %}
 | 
			
		||||
		</tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
		</div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
	{{ chill_pagination(pagination) }}
 | 
			
		||||
 | 
			
		||||
	{% if is_granted('CHILL_PERSON_DOCUMENT_CREATE', person) %}
 | 
			
		||||
		<ul class="record_actions">
 | 
			
		||||
		<ul class="record_actions sticky-form-buttons">
 | 
			
		||||
			<li class="create">
 | 
			
		||||
				<a href="{{ path('person_document_new', {'person': person.id}) }}" class="btn btn-create">
 | 
			
		||||
					{{ 'Create new document' | trans }}
 | 
			
		||||
@@ -85,4 +55,6 @@
 | 
			
		||||
			</li>
 | 
			
		||||
		</ul>
 | 
			
		||||
	{% endif %}
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
{% set activeRouteKey = '' %}
 | 
			
		||||
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
 | 
			
		||||
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
 | 
			
		||||
 | 
			
		||||
{% block title %}{{ 'Detail of document of %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %}
 | 
			
		||||
 | 
			
		||||
@@ -29,12 +30,16 @@
 | 
			
		||||
{% block personcontent %}
 | 
			
		||||
    <h1>{{ 'Document %title%' | trans({ '%title%': document.title }) }}</h1>
 | 
			
		||||
 | 
			
		||||
    {{ mm.mimeIcon(document.object.type) }}
 | 
			
		||||
 | 
			
		||||
    <dl class="chill_view_data">
 | 
			
		||||
        <dt>{{ 'Title'|trans }}</dt>
 | 
			
		||||
        <dd>{{ document.title }}</dd>
 | 
			
		||||
 | 
			
		||||
        {% if document.scope is not null %}
 | 
			
		||||
        <dt>{{ 'Scope' | trans }}</dt>
 | 
			
		||||
        <dd>{{ document.scope.name | localize_translatable_string }}</dd>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        <dt>{{ 'Category'|trans }}</dt>
 | 
			
		||||
        <dd>{{ document.category.name|localize_translatable_string }}</dd>
 | 
			
		||||
@@ -52,7 +57,7 @@
 | 
			
		||||
 | 
			
		||||
    </dl>
 | 
			
		||||
 | 
			
		||||
    <ul class="record_actions">
 | 
			
		||||
    <ul class="record_actions sticky-form-buttons">
 | 
			
		||||
        <li class="cancel">
 | 
			
		||||
            <a href="{{ path('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
 | 
			
		||||
                {{ 'Back to the list' | trans }}
 | 
			
		||||
@@ -63,6 +68,12 @@
 | 
			
		||||
            {{ m.download_button(document.object, document.title) }}
 | 
			
		||||
        </li>
 | 
			
		||||
 | 
			
		||||
        {% if chill_document_is_editable(document.object) %}
 | 
			
		||||
            <li>
 | 
			
		||||
                {{ document.object|chill_document_edit_button }}
 | 
			
		||||
            </li>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
 | 
			
		||||
        {% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
 | 
			
		||||
            <li>
 | 
			
		||||
                <a href="{{ path('person_document_edit', {'id': document.id, 'person': person.id}) }}" class="btn btn-edit">
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
<?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\DocStoreBundle\Templating;
 | 
			
		||||
 | 
			
		||||
use Twig\Extension\AbstractExtension;
 | 
			
		||||
use Twig\TwigFilter;
 | 
			
		||||
use Twig\TwigFunction;
 | 
			
		||||
 | 
			
		||||
class WopiEditTwigExtension extends AbstractExtension
 | 
			
		||||
{
 | 
			
		||||
    public function getFilters(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            new TwigFilter('chill_document_edit_button', [WopiEditTwigExtensionRuntime::class, 'renderEditButton'], [
 | 
			
		||||
                'needs_environment' => true,
 | 
			
		||||
                'is_safe' => ['html'],
 | 
			
		||||
            ]),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getFunctions(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            new TwigFunction('chill_document_is_editable', [WopiEditTwigExtensionRuntime::class, 'isEditable']),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
<?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\DocStoreBundle\Templating;
 | 
			
		||||
 | 
			
		||||
use ChampsLibres\WopiLib\Contract\Service\Discovery\DiscoveryInterface;
 | 
			
		||||
use Chill\DocStoreBundle\Entity\StoredObject;
 | 
			
		||||
use Twig\Environment;
 | 
			
		||||
use Twig\Extension\RuntimeExtensionInterface;
 | 
			
		||||
use function array_key_exists;
 | 
			
		||||
 | 
			
		||||
class WopiEditTwigExtensionRuntime implements RuntimeExtensionInterface
 | 
			
		||||
{
 | 
			
		||||
    public const TEMPLATE = '@ChillDocStore/Button/wopi_edit_document.html.twig';
 | 
			
		||||
 | 
			
		||||
    private DiscoveryInterface $discovery;
 | 
			
		||||
 | 
			
		||||
    public function __construct(DiscoveryInterface $discovery)
 | 
			
		||||
    {
 | 
			
		||||
        $this->discovery = $discovery;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isEditable(StoredObject $document): bool
 | 
			
		||||
    {
 | 
			
		||||
        $mime_type = $this->discovery->discoverMimeType($document->getType());
 | 
			
		||||
 | 
			
		||||
        if ([] === $mime_type) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($mime_type as $item) {
 | 
			
		||||
            if (array_key_exists('default', $item) && 'true' === $item['default']) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function renderEditButton(Environment $environment, StoredObject $document, ?array $options = null): string
 | 
			
		||||
    {
 | 
			
		||||
        return $environment->render(self::TEMPLATE, [
 | 
			
		||||
            'document' => $document,
 | 
			
		||||
            'options' => $options,
 | 
			
		||||
        ]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,6 @@ services:
 | 
			
		||||
    autowire: true
 | 
			
		||||
    autoconfigure: true
 | 
			
		||||
    resource: "../Repository/"
 | 
			
		||||
    tags: ["doctrine.repository_service"]
 | 
			
		||||
 | 
			
		||||
  Chill\DocStoreBundle\Form\DocumentCategoryType:
 | 
			
		||||
    class: Chill\DocStoreBundle\Form\DocumentCategoryType
 | 
			
		||||
@@ -16,8 +15,10 @@ services:
 | 
			
		||||
 | 
			
		||||
  Chill\DocStoreBundle\Form\PersonDocumentType:
 | 
			
		||||
    class: Chill\DocStoreBundle\Form\PersonDocumentType
 | 
			
		||||
    arguments:
 | 
			
		||||
      - "@chill.main.helper.translatable_string"
 | 
			
		||||
    autowire: true
 | 
			
		||||
    autoconfigure: true
 | 
			
		||||
    # arguments:
 | 
			
		||||
    #   - "@chill.main.helper.translatable_string"
 | 
			
		||||
    tags:
 | 
			
		||||
      - { name: form.type, alias: chill_docstorebundle_form_document }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
services:
 | 
			
		||||
 | 
			
		||||
  Chill\DocStoreBundle\Templating\:
 | 
			
		||||
    resource: ../../Templating
 | 
			
		||||
    autoconfigure: true
 | 
			
		||||
    autowire: true
 | 
			
		||||
@@ -0,0 +1,76 @@
 | 
			
		||||
<?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\Migrations\DocStore;
 | 
			
		||||
 | 
			
		||||
use Doctrine\DBAL\Schema\Schema;
 | 
			
		||||
use Doctrine\Migrations\AbstractMigration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implementations of create and update traits for Document entity + template property added.
 | 
			
		||||
 */
 | 
			
		||||
final class Version20220131093117 extends AbstractMigration
 | 
			
		||||
{
 | 
			
		||||
    public function down(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP CONSTRAINT FK_41DA53C5DA0FB8');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP CONSTRAINT FK_41DA53C3174800F');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP CONSTRAINT FK_41DA53C65FF1AEC');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP template_id');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP createdAt');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP updatedAt');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP createdBy_id');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document DROP updatedBy_id');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F65DA0FB8');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F63174800F');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F665FF1AEC');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP template_id');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP createdAt');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP updatedAt');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP createdBy_id');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP updatedBy_id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getDescription(): string
 | 
			
		||||
    {
 | 
			
		||||
        return 'Implementations of create and update traits for Document entity + template property added';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function up(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD template_id INT DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD createdBy_id INT DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD updatedBy_id INT DEFAULT NULL');
 | 
			
		||||
        $this->addSql('COMMENT ON COLUMN chill_doc.accompanyingcourse_document.createdAt IS \'(DC2Type:datetime_immutable)\'');
 | 
			
		||||
        $this->addSql('COMMENT ON COLUMN chill_doc.accompanyingcourse_document.updatedAt IS \'(DC2Type:datetime_immutable)\'');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F65DA0FB8 FOREIGN KEY (template_id) REFERENCES chill_docgen_template (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F63174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F665FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('CREATE INDEX IDX_A45098F65DA0FB8 ON chill_doc.accompanyingcourse_document (template_id)');
 | 
			
		||||
        $this->addSql('CREATE INDEX IDX_A45098F63174800F ON chill_doc.accompanyingcourse_document (createdBy_id)');
 | 
			
		||||
        $this->addSql('CREATE INDEX IDX_A45098F665FF1AEC ON chill_doc.accompanyingcourse_document (updatedBy_id)');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD template_id INT DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD createdBy_id INT DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD updatedBy_id INT DEFAULT NULL');
 | 
			
		||||
        $this->addSql('COMMENT ON COLUMN chill_doc.person_document.createdAt IS \'(DC2Type:datetime_immutable)\'');
 | 
			
		||||
        $this->addSql('COMMENT ON COLUMN chill_doc.person_document.updatedAt IS \'(DC2Type:datetime_immutable)\'');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C5DA0FB8 FOREIGN KEY (template_id) REFERENCES chill_docgen_template (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('CREATE INDEX IDX_41DA53C5DA0FB8 ON chill_doc.person_document (template_id)');
 | 
			
		||||
        $this->addSql('CREATE INDEX IDX_41DA53C3174800F ON chill_doc.person_document (createdBy_id)');
 | 
			
		||||
        $this->addSql('CREATE INDEX IDX_41DA53C65FF1AEC ON chill_doc.person_document (updatedBy_id)');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,6 +10,7 @@ New document for %name%: Nouveau document pour %name%
 | 
			
		||||
Editing document for %name%: Modification d'un document pour %name%
 | 
			
		||||
Edit Document: Modification d'un document
 | 
			
		||||
Update document: Modifier le document
 | 
			
		||||
Edit attributes: Modifier les propriétés du document
 | 
			
		||||
Existing document: Document existant
 | 
			
		||||
No document to download: Aucun document à télécharger
 | 
			
		||||
'Choose a document category': Choisissez une catégorie de document
 | 
			
		||||
@@ -51,4 +52,7 @@ Id inside bundle: Identifiant
 | 
			
		||||
Document class: Classe de document
 | 
			
		||||
no records found:
 | 
			
		||||
Create new category: Créer une nouvelle catégorie
 | 
			
		||||
Back to the category list: Retour à la liste
 | 
			
		||||
Back to the category list: Retour à la liste
 | 
			
		||||
 | 
			
		||||
# WOPI EDIT
 | 
			
		||||
online_edit_document: Éditer en ligne
 | 
			
		||||
 
 | 
			
		||||
@@ -15,19 +15,13 @@ use Chill\AMLI\FamilyMembersBundle\Security\Voter\FamilyMemberVoter;
 | 
			
		||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
 | 
			
		||||
use Knp\Menu\MenuItem;
 | 
			
		||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
 | 
			
		||||
use Symfony\Component\Translation\TranslatorInterface;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 | 
			
		||||
class UserMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var AuthorizationCheckerInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $authorizationChecker;
 | 
			
		||||
    protected AuthorizationCheckerInterface $authorizationChecker;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TranslatorInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $translator;
 | 
			
		||||
    protected TranslatorInterface $translator;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        AuthorizationCheckerInterface $authorizationChecker,
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,8 @@ declare(strict_types=1);
 | 
			
		||||
namespace Chill\MainBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\CRUD\Controller\ApiController;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorInterface;
 | 
			
		||||
use Doctrine\ORM\QueryBuilder;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -19,7 +21,7 @@ use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
 */
 | 
			
		||||
class LocationApiController extends ApiController
 | 
			
		||||
{
 | 
			
		||||
    public function customizeQuery(string $action, Request $request, $query): void
 | 
			
		||||
    protected function customizeQuery(string $action, Request $request, $query): void
 | 
			
		||||
    {
 | 
			
		||||
        $query
 | 
			
		||||
            ->leftJoin('e.locationType', 'lt')
 | 
			
		||||
@@ -31,4 +33,14 @@ class LocationApiController extends ApiController
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param QueryBuilder $query
 | 
			
		||||
     * @param mixed $_format
 | 
			
		||||
     */
 | 
			
		||||
    protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
 | 
			
		||||
    {
 | 
			
		||||
        return $query
 | 
			
		||||
            ->addOrderBy('e.name', 'ASC');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -236,6 +236,10 @@ class NotificationController extends AbstractController
 | 
			
		||||
                        '_fragment' => 'comment-' . $commentId,
 | 
			
		||||
                    ]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($editedCommentForm->isSubmitted() && !$editedCommentForm->isValid()) {
 | 
			
		||||
                    $this->addFlash('error', $this->translator->trans('This form contains errors'));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -257,6 +261,10 @@ class NotificationController extends AbstractController
 | 
			
		||||
                        'id' => $notification->getId(),
 | 
			
		||||
                    ]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($appendCommentForm->isSubmitted() && !$appendCommentForm->isValid()) {
 | 
			
		||||
                    $this->addFlash('error', $this->translator->trans('This form contains errors'));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
 | 
			
		||||
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\EntityWorkflowVoter;
 | 
			
		||||
use Chill\MainBundle\Workflow\EntityWorkflowManager;
 | 
			
		||||
use Chill\MainBundle\Workflow\Validator\StepDestValid;
 | 
			
		||||
use Doctrine\ORM\EntityManagerInterface;
 | 
			
		||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
@@ -166,6 +167,7 @@ class WorkflowController extends AbstractController
 | 
			
		||||
 | 
			
		||||
        $handler = $this->entityWorkflowManager->getHandler($entityWorkflow);
 | 
			
		||||
        $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
 | 
			
		||||
        $errors = [];
 | 
			
		||||
 | 
			
		||||
        if (count($workflow->getEnabledTransitions($entityWorkflow)) > 0) {
 | 
			
		||||
            // possible transition
 | 
			
		||||
@@ -201,9 +203,18 @@ class WorkflowController extends AbstractController
 | 
			
		||||
                    $entityWorkflow->getCurrentStep()->addDestUser($user);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $this->entityManager->flush();
 | 
			
		||||
                $errors = $this->validator->validate(
 | 
			
		||||
                    $entityWorkflow->getCurrentStep(),
 | 
			
		||||
                    new StepDestValid()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
 | 
			
		||||
                if (count($errors) === 0) {
 | 
			
		||||
                    $this->entityManager->flush();
 | 
			
		||||
 | 
			
		||||
                    return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return new Response((string) $errors, Response::HTTP_UNPROCESSABLE_ENTITY);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($transitionForm->isSubmitted() && !$transitionForm->isValid()) {
 | 
			
		||||
@@ -235,6 +246,7 @@ class WorkflowController extends AbstractController
 | 
			
		||||
                'handler_template_data' => $handler->getTemplateData($entityWorkflow),
 | 
			
		||||
                'transition_form' => isset($transitionForm) ? $transitionForm->createView() : null,
 | 
			
		||||
                'entity_workflow' => $entityWorkflow,
 | 
			
		||||
                'transition_form_errors' => $errors,
 | 
			
		||||
                //'comment_form' => $commentForm->createView(),
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ use DateTimeInterface;
 | 
			
		||||
use Doctrine\ORM\Event\LifecycleEventArgs;
 | 
			
		||||
use Doctrine\ORM\Event\PreFlushEventArgs;
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Symfony\Component\Validator\Constraints as Assert;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\Entity
 | 
			
		||||
@@ -28,6 +29,7 @@ class NotificationComment implements TrackCreationInterface, TrackUpdateInterfac
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="text")
 | 
			
		||||
     * @Assert\NotBlank(message="notification.Comment content might not be blank")
 | 
			
		||||
     */
 | 
			
		||||
    private string $content = '';
 | 
			
		||||
 | 
			
		||||
@@ -136,9 +138,9 @@ class NotificationComment implements TrackCreationInterface, TrackUpdateInterfac
 | 
			
		||||
        $this->recentlyPersisted = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setContent(string $content): self
 | 
			
		||||
    public function setContent(?string $content): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->content = $content;
 | 
			
		||||
        $this->content = (string) $content;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -135,6 +135,7 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
 | 
			
		||||
        if (!$this->steps->contains($step)) {
 | 
			
		||||
            $this->steps[] = $step;
 | 
			
		||||
            $step->setEntityWorkflow($this);
 | 
			
		||||
            $this->stepsChainedCache = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
@@ -174,6 +175,20 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getCurrentStepChained(): ?EntityWorkflowStep
 | 
			
		||||
    {
 | 
			
		||||
        $steps = $this->getStepsChained();
 | 
			
		||||
        $currentStep = $this->getCurrentStep();
 | 
			
		||||
 | 
			
		||||
        foreach ($steps as $step) {
 | 
			
		||||
            if ($step === $currentStep) {
 | 
			
		||||
                return $step;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getCurrentStepCreatedAt(): ?DateTimeInterface
 | 
			
		||||
    {
 | 
			
		||||
        if (null !== $previous = $this->getPreviousStepIfAny()) {
 | 
			
		||||
@@ -318,32 +333,26 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
 | 
			
		||||
 | 
			
		||||
    public function isFinal(): bool
 | 
			
		||||
    {
 | 
			
		||||
        $steps = $this->getStepsChained();
 | 
			
		||||
 | 
			
		||||
        if (1 === count($steps)) {
 | 
			
		||||
            // the initial step cannot be finalized
 | 
			
		||||
            return false;
 | 
			
		||||
        foreach ($this->getStepsChained() as $step) {
 | 
			
		||||
            if ($step->isFinal()) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /** @var EntityWorkflowStep $last */
 | 
			
		||||
        $last = end($steps);
 | 
			
		||||
 | 
			
		||||
        return $last->isFinal();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isFreeze(): bool
 | 
			
		||||
    {
 | 
			
		||||
        $steps = $this->getStepsChained();
 | 
			
		||||
 | 
			
		||||
        if (1 === count($steps)) {
 | 
			
		||||
            // the initial step cannot be finalized
 | 
			
		||||
            return false;
 | 
			
		||||
        foreach ($this->getStepsChained() as $step) {
 | 
			
		||||
            if ($step->isFreezeAfter()) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /** @var EntityWorkflowStep $last */
 | 
			
		||||
        $last = end($steps);
 | 
			
		||||
 | 
			
		||||
        return $last->getPrevious()->isFreezeAfter();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isUserSubscribedToFinal(User $user): bool
 | 
			
		||||
@@ -420,7 +429,7 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
 | 
			
		||||
        $newStep->setCurrentStep($step);
 | 
			
		||||
 | 
			
		||||
        // copy the freeze
 | 
			
		||||
        if ($this->getCurrentStep()->isFreezeAfter()) {
 | 
			
		||||
        if ($this->isFreeze()) {
 | 
			
		||||
            $newStep->setFreezeAfter(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,8 @@ class WorkflowStepType extends AbstractType
 | 
			
		||||
        $entityWorkflow = $options['entity_workflow'];
 | 
			
		||||
        $handler = $this->entityWorkflowManager->getHandler($entityWorkflow);
 | 
			
		||||
        $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
 | 
			
		||||
        $place = $workflow->getMarking($entityWorkflow);
 | 
			
		||||
        $placeMetadata = $workflow->getMetadataStore()->getPlaceMetadata(array_keys($place->getPlaces())[0]);
 | 
			
		||||
 | 
			
		||||
        if (true === $options['transition']) {
 | 
			
		||||
            if (null === $options['entity_workflow']) {
 | 
			
		||||
@@ -68,40 +70,77 @@ class WorkflowStepType extends AbstractType
 | 
			
		||||
                $transitions
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            if (array_key_exists('validationFilterInputLabels', $placeMetadata)) {
 | 
			
		||||
                $inputLabels = $placeMetadata['validationFilterInputLabels'];
 | 
			
		||||
 | 
			
		||||
                $builder->add('transitionFilter', ChoiceType::class, [
 | 
			
		||||
                    'multiple' => false,
 | 
			
		||||
                    'label' => 'workflow.My decision',
 | 
			
		||||
                    'choices' => [
 | 
			
		||||
                        'forward' => 'forward',
 | 
			
		||||
                        'backward' => 'backward',
 | 
			
		||||
                        'neutral' => 'neutral',
 | 
			
		||||
                    ],
 | 
			
		||||
                    'choice_label' => function (string $key) use ($inputLabels) {
 | 
			
		||||
                        return $this->translatableStringHelper->localize($inputLabels[$key]);
 | 
			
		||||
                    },
 | 
			
		||||
                    'choice_attr' => static function (string $key) {
 | 
			
		||||
                        return [
 | 
			
		||||
                            $key => $key,
 | 
			
		||||
                        ];
 | 
			
		||||
                    },
 | 
			
		||||
                    'mapped' => false,
 | 
			
		||||
                    'expanded' => true,
 | 
			
		||||
                    'data' => 'forward',
 | 
			
		||||
                ]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $builder
 | 
			
		||||
                ->add('transition', ChoiceType::class, [
 | 
			
		||||
                    'label' => 'workflow.Transition to apply',
 | 
			
		||||
                    'label' => 'workflow.Next step',
 | 
			
		||||
                    'mapped' => false,
 | 
			
		||||
                    'multiple' => false,
 | 
			
		||||
                    'expanded' => true,
 | 
			
		||||
                    'choices' => $choices,
 | 
			
		||||
                    'choice_label' => function (Transition $transition) use ($workflow) {
 | 
			
		||||
                            $meta = $workflow->getMetadataStore()->getTransitionMetadata($transition);
 | 
			
		||||
                        $meta = $workflow->getMetadataStore()->getTransitionMetadata($transition);
 | 
			
		||||
 | 
			
		||||
                            if (array_key_exists('label', $meta)) {
 | 
			
		||||
                                return $this->translatableStringHelper->localize($meta['label']);
 | 
			
		||||
                            }
 | 
			
		||||
                        if (array_key_exists('label', $meta)) {
 | 
			
		||||
                            return $this->translatableStringHelper->localize($meta['label']);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                            return $transition->getName();
 | 
			
		||||
                        },
 | 
			
		||||
                        return $transition->getName();
 | 
			
		||||
                    },
 | 
			
		||||
                    'choice_attr' => static function (Transition $transition) use ($workflow) {
 | 
			
		||||
                            $toFinal = true;
 | 
			
		||||
                        $toFinal = true;
 | 
			
		||||
                        $isForward = 'neutral';
 | 
			
		||||
 | 
			
		||||
                            foreach ($transition->getTos() as $to) {
 | 
			
		||||
                                $meta = $workflow->getMetadataStore()->getPlaceMetadata($to);
 | 
			
		||||
                        $metadata = $workflow->getMetadataStore()->getTransitionMetadata($transition);
 | 
			
		||||
 | 
			
		||||
                                if (
 | 
			
		||||
                        if (array_key_exists('isForward', $metadata)) {
 | 
			
		||||
                            if ($metadata['isForward']) {
 | 
			
		||||
                                $isForward = 'forward';
 | 
			
		||||
                            } else {
 | 
			
		||||
                                $isForward = 'backward';
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        foreach ($transition->getTos() as $to) {
 | 
			
		||||
                            $meta = $workflow->getMetadataStore()->getPlaceMetadata($to);
 | 
			
		||||
 | 
			
		||||
                            if (
 | 
			
		||||
                                    !array_key_exists('isFinal', $meta) || false === $meta['isFinal']
 | 
			
		||||
                                ) {
 | 
			
		||||
                                    $toFinal = false;
 | 
			
		||||
                                }
 | 
			
		||||
                                $toFinal = false;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                            return [
 | 
			
		||||
                                'data-is-transition' => 'data-is-transition',
 | 
			
		||||
                                'data-to-final' => $toFinal ? '1' : '0',
 | 
			
		||||
                            ];
 | 
			
		||||
                        },
 | 
			
		||||
                        return [
 | 
			
		||||
                            'data-is-transition' => 'data-is-transition',
 | 
			
		||||
                            'data-to-final' => $toFinal ? '1' : '0',
 | 
			
		||||
                            'data-is-forward' => $isForward,
 | 
			
		||||
                        ];
 | 
			
		||||
                    },
 | 
			
		||||
                ])
 | 
			
		||||
                ->add('future_dest_users', PickUserDynamicType::class, [
 | 
			
		||||
                    'label' => 'workflow.dest for next steps',
 | 
			
		||||
 
 | 
			
		||||
@@ -79,11 +79,8 @@ class NotificationMailer
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $email = new Email();
 | 
			
		||||
            $email
 | 
			
		||||
                ->subject($notification->getTitle());
 | 
			
		||||
 | 
			
		||||
            if ($notification->isSystem()) {
 | 
			
		||||
                $email = new Email();
 | 
			
		||||
                $email
 | 
			
		||||
                    ->text($notification->getMessage());
 | 
			
		||||
            } else {
 | 
			
		||||
@@ -96,7 +93,9 @@ class NotificationMailer
 | 
			
		||||
                    ]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $email->to($addressee->getEmail());
 | 
			
		||||
            $email
 | 
			
		||||
                ->subject($notification->getTitle())
 | 
			
		||||
                ->to($addressee->getEmail());
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                $this->mailer->send($email);
 | 
			
		||||
 
 | 
			
		||||
@@ -110,7 +110,8 @@ class EntityWorkflowRepository implements ObjectRepository
 | 
			
		||||
        $qb->where(
 | 
			
		||||
            $qb->expr()->andX(
 | 
			
		||||
                $qb->expr()->isMemberOf(':user', 'step.destUser'),
 | 
			
		||||
                $qb->expr()->isNull('step.transitionAfter')
 | 
			
		||||
                $qb->expr()->isNull('step.transitionAfter'),
 | 
			
		||||
                $qb->expr()->eq('step.isFinal', "'FALSE'")
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,79 @@
 | 
			
		||||
<?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\Repository\Workflow;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Entity\User;
 | 
			
		||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep;
 | 
			
		||||
use Doctrine\ORM\EntityManagerInterface;
 | 
			
		||||
use Doctrine\ORM\EntityRepository;
 | 
			
		||||
use Doctrine\ORM\QueryBuilder;
 | 
			
		||||
use Doctrine\Persistence\ObjectRepository;
 | 
			
		||||
 | 
			
		||||
class EntityWorkflowStepRepository implements ObjectRepository
 | 
			
		||||
{
 | 
			
		||||
    private EntityRepository $repository;
 | 
			
		||||
 | 
			
		||||
    public function __construct(EntityManagerInterface $entityManager)
 | 
			
		||||
    {
 | 
			
		||||
        $this->repository = $entityManager->getRepository(EntityWorkflowStep::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function countUnreadByUser(User $user, ?array $orderBy = null, $limit = null, $offset = null): int
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->buildQueryByUser($user)->select('count(e)');
 | 
			
		||||
 | 
			
		||||
        return (int) $qb->getQuery()->getSingleScalarResult();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function find($id): ?EntityWorkflowStep
 | 
			
		||||
    {
 | 
			
		||||
        return $this->repository->find($id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findAll(): array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->repository->findAll();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findOneBy(array $criteria): ?EntityWorkflowStep
 | 
			
		||||
    {
 | 
			
		||||
        return $this->repository->findOneBy($criteria);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getClassName()
 | 
			
		||||
    {
 | 
			
		||||
        return EntityWorkflowStep::class;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function buildQueryByUser(User $user): QueryBuilder
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->repository->createQueryBuilder('e');
 | 
			
		||||
 | 
			
		||||
        $qb->where(
 | 
			
		||||
            $qb->expr()->andX(
 | 
			
		||||
                $qb->expr()->isMemberOf(':user', 'e.destUser'),
 | 
			
		||||
                $qb->expr()->isNull('e.transitionAt'),
 | 
			
		||||
                $qb->expr()->eq('e.isFinal', ':bool'),
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $qb->setParameter('user', $user);
 | 
			
		||||
        $qb->setParameter('bool', false);
 | 
			
		||||
 | 
			
		||||
        return $qb;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -25,6 +25,7 @@ import { chill } from './js/chill.js';
 | 
			
		||||
global.chill = chill;
 | 
			
		||||
 | 
			
		||||
require('./js/date.js');
 | 
			
		||||
require('./js/counter.js');
 | 
			
		||||
 | 
			
		||||
/// Load fonts
 | 
			
		||||
require('./fonts/OpenSans/OpenSans.scss')
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * This script search for span.counter elements like
 | 
			
		||||
 *   <span class="counter">Il y a 4 notifications</span>
 | 
			
		||||
 * and return
 | 
			
		||||
 *   <span class="counter">Il y a <span>4</span> notifications</span>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
const isNum = (v) => !isNaN(v);
 | 
			
		||||
 | 
			
		||||
const parseCounter = () => {
 | 
			
		||||
    document.querySelectorAll('span.counter')
 | 
			
		||||
        .forEach(el => {
 | 
			
		||||
            let r = [];
 | 
			
		||||
            el.innerText
 | 
			
		||||
                .trim()
 | 
			
		||||
                .split(' ')
 | 
			
		||||
                .forEach(w => {
 | 
			
		||||
                    if (isNum(w)) {
 | 
			
		||||
                        r.push(`<span>${w}</span>`);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        r.push(w);
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
            ;
 | 
			
		||||
            el.innerHTML = r.join(' ');
 | 
			
		||||
        })
 | 
			
		||||
    ;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
window.addEventListener('DOMContentLoaded', function (e) {
 | 
			
		||||
    parseCounter();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export { parseCounter };
 | 
			
		||||
@@ -15,6 +15,7 @@ $chill-theme-buttons: (
 | 
			
		||||
   "action":        $chill-orange,
 | 
			
		||||
   "edit":          $chill-orange,
 | 
			
		||||
   "update":        $chill-orange,
 | 
			
		||||
   "wopilink":      $chill-orange,
 | 
			
		||||
   "show":          $chill-blue,
 | 
			
		||||
   "view":          $chill-blue,
 | 
			
		||||
   "misc":          $gray-300,
 | 
			
		||||
@@ -54,6 +55,7 @@ $chill-theme-buttons: (
 | 
			
		||||
   &.btn-action,
 | 
			
		||||
   &.btn-edit,
 | 
			
		||||
   &.btn-tpchild,
 | 
			
		||||
   &.btn-wopilink,
 | 
			
		||||
   &.btn-update {
 | 
			
		||||
       &, &:hover {
 | 
			
		||||
          color: $light;
 | 
			
		||||
@@ -66,6 +68,7 @@ $chill-theme-buttons: (
 | 
			
		||||
   &.btn-create::before,
 | 
			
		||||
   &.btn-edit::before,
 | 
			
		||||
   &.btn-update::before,
 | 
			
		||||
   &.btn-wopilink::before,
 | 
			
		||||
   &.btn-show::before,
 | 
			
		||||
   &.btn-view::before,
 | 
			
		||||
   &.btn-save::before,
 | 
			
		||||
@@ -98,6 +101,7 @@ $chill-theme-buttons: (
 | 
			
		||||
   &.btn-create::before    { content: "\f067"; } // fa-plus
 | 
			
		||||
   &.btn-edit::before,
 | 
			
		||||
   &.btn-update::before    { content: "\f040"; } // fa-pencil
 | 
			
		||||
   &.btn-wopilink::before  { content: "\f1dd"; } // fa-paragraph
 | 
			
		||||
   &.btn-show::before,
 | 
			
		||||
   &.btn-view::before      { content: "\f06e"; } // fa-eye
 | 
			
		||||
   &.btn-save::before      { content: "\f0c7"; } // fa-floppy-o
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@ div#notification-fold {
 | 
			
		||||
 | 
			
		||||
// Counter
 | 
			
		||||
div.notification-counter {
 | 
			
		||||
    span {
 | 
			
		||||
    span.counter {
 | 
			
		||||
        &:not(:first-child) {
 | 
			
		||||
            &::before {
 | 
			
		||||
                content: '/ ';
 | 
			
		||||
@@ -90,3 +90,11 @@ div.notification-counter {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
span.counter {
 | 
			
		||||
    & > span {
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        background-color: $chill-ll-gray;
 | 
			
		||||
        padding: 0 0.4rem;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,19 +1,19 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Create a control to show or hide values
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Possible options are:
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 *  - froms: an Element, an Array of Element, or a NodeList. A
 | 
			
		||||
 *    listener will be attached to **all** input of those elements
 | 
			
		||||
 *    and will trigger the check on changes
 | 
			
		||||
 *  - test: a function which will test the element and will return true 
 | 
			
		||||
 *  - test: a function which will test the element and will return true
 | 
			
		||||
 *    if the content must be shown, false if it must be hidden.
 | 
			
		||||
 *    The function will receive the `froms` as first argument, and the 
 | 
			
		||||
 *    The function will receive the `froms` as first argument, and the
 | 
			
		||||
 *    event as second argument.
 | 
			
		||||
 *  - container: an Element, an Array of Element, or a Node List. The 
 | 
			
		||||
 *  - container: an Element, an Array of Element, or a Node List. The
 | 
			
		||||
 *    child nodes will be hidden / shown inside this container
 | 
			
		||||
 *  - event_name: the name of the event to listen to. `'change'` by default.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * @param object options
 | 
			
		||||
 */
 | 
			
		||||
var ShowHide = function(options) {
 | 
			
		||||
@@ -26,8 +26,10 @@ var ShowHide = function(options) {
 | 
			
		||||
        container_content = [],
 | 
			
		||||
        debug = 'debug' in options ? options.debug : false,
 | 
			
		||||
        load_event = 'load_event' in options ? options.load_event : 'load',
 | 
			
		||||
        id = 'uid' in options ? options.id : Math.random();
 | 
			
		||||
    
 | 
			
		||||
        id = 'uid' in options ? options.id : Math.random(),
 | 
			
		||||
        toggle_callback = 'toggle_callback' in options ? options.toggle_callback : null
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
    var bootstrap = function(event) {
 | 
			
		||||
        if (debug) {
 | 
			
		||||
            console.log('debug is activated on this show-hide', this);
 | 
			
		||||
@@ -39,15 +41,14 @@ var ShowHide = function(options) {
 | 
			
		||||
                contents.push(el);
 | 
			
		||||
            }
 | 
			
		||||
            container_content.push(contents);
 | 
			
		||||
            // console.log('container content', container_content);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // attach the listener on each input
 | 
			
		||||
        for (let f of froms.values()) {
 | 
			
		||||
            let 
 | 
			
		||||
                inputs = f.querySelectorAll('input'), 
 | 
			
		||||
            let
 | 
			
		||||
                inputs = f.querySelectorAll('input'),
 | 
			
		||||
                selects = f.querySelectorAll('select');
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
            for (let input of inputs.values()) {
 | 
			
		||||
                if (debug) {
 | 
			
		||||
                    console.log('attaching event to input', input);
 | 
			
		||||
@@ -67,10 +68,10 @@ var ShowHide = function(options) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // first launch of the show/hide
 | 
			
		||||
        onChange(event);    
 | 
			
		||||
        onChange(event);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    var onChange = function (event) {
 | 
			
		||||
        var result = test(froms, event), me;
 | 
			
		||||
 | 
			
		||||
@@ -89,45 +90,53 @@ var ShowHide = function(options) {
 | 
			
		||||
        } else {
 | 
			
		||||
            throw "the result of test is not a boolean";
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    var forceHide = function() {
 | 
			
		||||
        if (debug) {
 | 
			
		||||
            console.log('force hide');
 | 
			
		||||
        }
 | 
			
		||||
        for (let contents of container_content.values()) {
 | 
			
		||||
            for (let el of contents.values()) {
 | 
			
		||||
                el.remove();
 | 
			
		||||
        if (toggle_callback !== null) {
 | 
			
		||||
            toggle_callback(container, 'hide');
 | 
			
		||||
        } else {
 | 
			
		||||
            for (let contents of container_content.values()) {
 | 
			
		||||
                for (let el of contents.values()) {
 | 
			
		||||
                    el.remove();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        is_shown = false;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    var forceShow = function() {
 | 
			
		||||
        if (debug) {
 | 
			
		||||
            console.log('show');
 | 
			
		||||
        }
 | 
			
		||||
        for (let i of container_content.keys()) {
 | 
			
		||||
            var contents = container_content[i];
 | 
			
		||||
            for (let el of contents.values()) {
 | 
			
		||||
                container[i].appendChild(el);
 | 
			
		||||
        if (toggle_callback !== null) {
 | 
			
		||||
            toggle_callback(container, 'show');
 | 
			
		||||
        } else {
 | 
			
		||||
            for (let i of container_content.keys()) {
 | 
			
		||||
                var contents = container_content[i];
 | 
			
		||||
                for (let el of contents.values()) {
 | 
			
		||||
                    container[i].appendChild(el);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        is_shown = true;
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    var forceCompute = function(event) {
 | 
			
		||||
        onChange(event);
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (load_event !== null) {
 | 
			
		||||
        window.addEventListener('load', bootstrap);
 | 
			
		||||
    } else {
 | 
			
		||||
        bootstrap(null);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        forceHide: forceHide,
 | 
			
		||||
        forceShow: forceShow,
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,12 @@ function loadDynamicPicker(element) {
 | 
			
		||||
            isMultiple = parseInt(el.dataset.multiple) === 1,
 | 
			
		||||
            uniqId = el.dataset.uniqid,
 | 
			
		||||
            input = element.querySelector('[data-input-uniqid="'+ el.dataset.uniqid +'"]'),
 | 
			
		||||
            picked = (isMultiple) ? (JSON.parse(input.value)) : ((input.value === '[]') ? (null) : ([JSON.parse(input.value)]));
 | 
			
		||||
            picked = isMultiple ?
 | 
			
		||||
                JSON.parse(input.value) : (
 | 
			
		||||
                    (input.value === '[]' || input.value === '') ?
 | 
			
		||||
                        null : [ JSON.parse(input.value) ]
 | 
			
		||||
                )
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
        if (!isMultiple) {
 | 
			
		||||
            if (input.value === '[]'){
 | 
			
		||||
 
 | 
			
		||||
@@ -4,20 +4,34 @@ import {_createI18n} from "ChillMainAssets/vuejs/_js/i18n";
 | 
			
		||||
 | 
			
		||||
const i18n = _createI18n({});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//TODO move to chillDocStore or ChillWopi
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
tags to load module:
 | 
			
		||||
 | 
			
		||||
<span data-module="wopi-link"
 | 
			
		||||
    data-wopi-url="{{ path('chill_wopi_file_edit', {'fileId': document.uuid}) }}"
 | 
			
		||||
    data-doc-type="{{ document.type|e('html_attr') }}"
 | 
			
		||||
    data-options="{{ options|json_encode }}"
 | 
			
		||||
        ></span>
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
window.addEventListener('DOMContentLoaded', function (e) {
 | 
			
		||||
    document.querySelectorAll('span[data-module="wopi-link"]')
 | 
			
		||||
        .forEach(function (el) {
 | 
			
		||||
            createApp({
 | 
			
		||||
                template: '<open-wopi-link :wopiUrl="wopiUrl" :title="title" :type="type" :button="button"></open-wopi-link>',
 | 
			
		||||
                template: '<open-wopi-link :wopiUrl="wopiUrl" :type="type" :options="options"></open-wopi-link>',
 | 
			
		||||
                components: {
 | 
			
		||||
                    OpenWopiLink
 | 
			
		||||
                },
 | 
			
		||||
                data() {
 | 
			
		||||
                    return {
 | 
			
		||||
                        wopiUrl: el.dataset.wopiUrl,
 | 
			
		||||
                        title: el.dataset.docTitle,
 | 
			
		||||
                        type: el.dataset.docType,
 | 
			
		||||
                        button: el.dataset.button ? JSON.parse(el.dataset.button) : {}
 | 
			
		||||
                        options: el.dataset.options !== 'null' ? JSON.parse(el.dataset.options) : {}
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
@@ -26,4 +40,4 @@ window.addEventListener('DOMContentLoaded', function (e) {
 | 
			
		||||
            ;
 | 
			
		||||
        })
 | 
			
		||||
    ;
 | 
			
		||||
});
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -2,29 +2,89 @@ import {ShowHide} from 'ChillMainAssets/lib/show_hide/show_hide.js';
 | 
			
		||||
 | 
			
		||||
window.addEventListener('DOMContentLoaded', function() {
 | 
			
		||||
    let
 | 
			
		||||
        finalizeAfterContainer = document.querySelector('#finalizeAfter'),
 | 
			
		||||
        divTransitions = document.querySelector('#transitions'),
 | 
			
		||||
        futureDestUsersContainer = document.querySelector('#futureDestUsers')
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
    if (null === finalizeAfterContainer) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    new ShowHide({
 | 
			
		||||
        load_event: null,
 | 
			
		||||
        froms: [finalizeAfterContainer],
 | 
			
		||||
        container: [futureDestUsersContainer],
 | 
			
		||||
        test: function(containers, arg2, arg3) {
 | 
			
		||||
            for (let container of containers) {
 | 
			
		||||
                for (let input of container.querySelectorAll('input')) {
 | 
			
		||||
                    if (!input.checked) {
 | 
			
		||||
                        return true;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return false;
 | 
			
		||||
    if (null !== divTransitions) {
 | 
			
		||||
        new ShowHide({
 | 
			
		||||
            load_event: null,
 | 
			
		||||
            froms: [divTransitions],
 | 
			
		||||
            container: [futureDestUsersContainer],
 | 
			
		||||
            test: function(divs, arg2, arg3) {
 | 
			
		||||
                for (let div of divs) {
 | 
			
		||||
                    for (let input of div.querySelectorAll('input')) {
 | 
			
		||||
                        if (input.checked) {
 | 
			
		||||
                            if (input.dataset.toFinal === "1") {
 | 
			
		||||
                                return false;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                return true;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        },
 | 
			
		||||
    })
 | 
			
		||||
                return true;
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let
 | 
			
		||||
        transitionFilterContainer = document.querySelector('#transitionFilter'),
 | 
			
		||||
        transitions = document.querySelector('#transitions')
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
    if (null !== transitionFilterContainer) {
 | 
			
		||||
        transitions.querySelectorAll('.form-check').forEach(function(row) {
 | 
			
		||||
 | 
			
		||||
            const isForward = row.querySelector('input').dataset.isForward;
 | 
			
		||||
 | 
			
		||||
            new ShowHide({
 | 
			
		||||
                load_event: null,
 | 
			
		||||
                froms: [transitionFilterContainer],
 | 
			
		||||
                container: row,
 | 
			
		||||
                test: function (containers) {
 | 
			
		||||
                    for (let container of containers) {
 | 
			
		||||
                        for (let input of container.querySelectorAll('input')) {
 | 
			
		||||
                            if (input.checked) {
 | 
			
		||||
                                return isForward === input.value;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                toggle_callback: function (c, dir) {
 | 
			
		||||
                    for (let div of c) {
 | 
			
		||||
                        let input = div.querySelector('input');
 | 
			
		||||
                        if ('hide' === dir) {
 | 
			
		||||
                            input.checked = false;
 | 
			
		||||
                            input.disabled = true;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            input.disabled = false;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // validate form
 | 
			
		||||
    let form = document.querySelector('form[name="workflow_step"]');
 | 
			
		||||
 | 
			
		||||
    if (form === null) {
 | 
			
		||||
        console.error('form to validate not found');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    form.addEventListener('submit', function (event) {
 | 
			
		||||
        const datas = new FormData(event.target);
 | 
			
		||||
 | 
			
		||||
        if (datas.has('workflow_step[future_dest_users]')) {
 | 
			
		||||
            const dests = JSON.parse(datas.get('workflow_step[future_dest_users]'));
 | 
			
		||||
            if (dests === null || (dests instanceof Array && dests.length === 0)) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                console.log('no users!');
 | 
			
		||||
                window.alert('Indiquez un utilisateur pour traiter la prochaine étape.');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
         :deselect-label="$t('create_address')"
 | 
			
		||||
         :selected-label="$t('multiselect.selected_label')"
 | 
			
		||||
         @search-change="listenInputSearch"
 | 
			
		||||
         :internal-search="false"
 | 
			
		||||
         ref="addressSelector"
 | 
			
		||||
         @select="selectAddress"
 | 
			
		||||
         @remove="remove"
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
         :selected-label="$t('multiselect.selected_label')"
 | 
			
		||||
         :taggable="true"
 | 
			
		||||
         :multiple="false"
 | 
			
		||||
         :internal-search="false"
 | 
			
		||||
         @tag="addPostcode"
 | 
			
		||||
         :tagPlaceholder="$t('create_postal_code')"
 | 
			
		||||
         :loading="isLoading"
 | 
			
		||||
 
 | 
			
		||||
@@ -3,16 +3,38 @@
 | 
			
		||||
   <span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span>
 | 
			
		||||
   <tab-table v-else>
 | 
			
		||||
      <template v-slot:thead>
 | 
			
		||||
         <th scope="col">id</th>
 | 
			
		||||
         <th scope="col">Ouvert le</th>
 | 
			
		||||
         <th scope="col">Usagers concernés</th>
 | 
			
		||||
         <th scope="col">{{ $t('opening_date') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('social_issues') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('concerned_persons') }}</th>
 | 
			
		||||
         <th scope="col"></th>
 | 
			
		||||
         <th scope="col"></th>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-slot:tbody>
 | 
			
		||||
         <tr v-for="(c, i) in accompanyingCourses.results" :key="`course-${i}`">
 | 
			
		||||
            <td>{{ c.id}}</td>
 | 
			
		||||
            <td>{{ $d(c.openingDate.datetime, 'long') }}</td>
 | 
			
		||||
            <td>{{ c.participations.length }}</td>
 | 
			
		||||
            <td>{{ $d(c.openingDate.datetime, 'short') }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <span v-for="i in c.socialIssues"
 | 
			
		||||
                  class="chill-entity entity-social-issue">
 | 
			
		||||
                  <span class="badge bg-chill-l-gray text-dark">
 | 
			
		||||
                     {{ i.title.fr }}
 | 
			
		||||
                  </span>
 | 
			
		||||
               </span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <span v-for="p in c.participations" class="me-1" :key="p.person.id">
 | 
			
		||||
                  <on-the-fly
 | 
			
		||||
                     :type="p.person.type"
 | 
			
		||||
                     :id="p.person.id"
 | 
			
		||||
                     :buttonText="p.person.textAge"
 | 
			
		||||
                     :displayBadge="'true' === 'true'"
 | 
			
		||||
                     action="show">
 | 
			
		||||
                  </on-the-fly>
 | 
			
		||||
               </span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <span v-if="c.emergency" class="badge rounded-pill bg-danger me-1">{{ $t('emergency') }}</span>
 | 
			
		||||
               <span v-if="c.confidential" class="badge rounded-pill bg-danger">{{ $t('confidential') }}</span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <a class="btn btn-sm btn-show" :href="getUrl(c)">
 | 
			
		||||
                  {{ $t('show_entity', { entity: $t('the_course') }) }}
 | 
			
		||||
@@ -26,11 +48,13 @@
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import TabTable from "./TabTable";
 | 
			
		||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
   name: "MyAccompanyingCourses",
 | 
			
		||||
   components: {
 | 
			
		||||
      TabTable
 | 
			
		||||
      TabTable,
 | 
			
		||||
      OnTheFly,
 | 
			
		||||
   },
 | 
			
		||||
   computed: {
 | 
			
		||||
      ...mapState([
 | 
			
		||||
@@ -56,5 +80,7 @@ export default {
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
 | 
			
		||||
span.badge.rounded-pill.bg-danger {
 | 
			
		||||
   text-transform: uppercase;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -6,22 +6,34 @@
 | 
			
		||||
         <div class="custom1">
 | 
			
		||||
            <ul class="list-unstyled">
 | 
			
		||||
               <li v-if="counter.notifications > 0">
 | 
			
		||||
                  <b>{{ counter.notifications }}</b> {{ $t('counter.unread_notifications') }}
 | 
			
		||||
                  <i18n-t keypath="counter.unread_notifications" tag="span" :class="counterClass" :plural="counter.notifications">
 | 
			
		||||
                     <template v-slot:n><span>{{ counter.notifications }}</span></template>
 | 
			
		||||
                  </i18n-t>
 | 
			
		||||
               </li>
 | 
			
		||||
               <li v-if="counter.accompanyingCourses > 0">
 | 
			
		||||
                  <b>{{ counter.accompanyingCourses }}</b> {{ $t('counter.assignated_courses') }}
 | 
			
		||||
                  <i18n-t keypath="counter.assignated_courses" tag="span" :class="counterClass" :plural="counter.accompanyingCourses">
 | 
			
		||||
                     <template v-slot:n><span>{{ counter.accompanyingCourses }}</span></template>
 | 
			
		||||
                  </i18n-t>
 | 
			
		||||
               </li>
 | 
			
		||||
               <li v-if="counter.works > 0">
 | 
			
		||||
                  <b>{{ counter.works }}</b> {{ $t('counter.assignated_actions') }}
 | 
			
		||||
                  <i18n-t keypath="counter.assignated_actions" tag="span" :class="counterClass" :plural="counter.works">
 | 
			
		||||
                     <template v-slot:n><span>{{ counter.works }}</span></template>
 | 
			
		||||
                  </i18n-t>
 | 
			
		||||
               </li>
 | 
			
		||||
               <li v-if="counter.evaluations > 0">
 | 
			
		||||
                  <b>{{ counter.evaluations }}</b> {{ $t('counter.assignated_evaluations') }}
 | 
			
		||||
                  <i18n-t keypath="counter.assignated_evaluations" tag="span" :class="counterClass" :plural="counter.evaluations">
 | 
			
		||||
                     <template v-slot:n><span>{{ counter.evaluations }}</span></template>
 | 
			
		||||
                  </i18n-t>
 | 
			
		||||
               </li>
 | 
			
		||||
               <li v-if="counter.tasksAlert > 0">
 | 
			
		||||
                  <b>{{ counter.tasksAlert }}</b> {{ $t('counter.alert_tasks') }}
 | 
			
		||||
                  <i18n-t keypath="counter.alert_tasks" tag="span" :class="counterClass" :plural="counter.tasksAlert">
 | 
			
		||||
                     <template v-slot:n><span>{{ counter.tasksAlert }}</span></template>
 | 
			
		||||
                  </i18n-t>
 | 
			
		||||
               </li>
 | 
			
		||||
               <li v-if="counter.tasksWarning > 0">
 | 
			
		||||
                  <b>{{ counter.tasksWarning }}</b> {{ $t('counter.warning_tasks') }}
 | 
			
		||||
                  <i18n-t keypath="counter.warning_tasks" tag="span" :class="counterClass" :plural="counter.tasksWarning">
 | 
			
		||||
                     <template v-slot:n><span>{{ counter.tasksWarning }}</span></template>
 | 
			
		||||
                  </i18n-t>
 | 
			
		||||
               </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
         </div>
 | 
			
		||||
@@ -54,6 +66,13 @@ import Masonry from 'masonry-layout/masonry';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
   name: "MyCustoms",
 | 
			
		||||
   data() {
 | 
			
		||||
      return {
 | 
			
		||||
         counterClass: {
 | 
			
		||||
            counter: true   //hack to pass class 'counter' in i18n-t
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
   },
 | 
			
		||||
   computed: {
 | 
			
		||||
      ...mapGetters(['counter']),
 | 
			
		||||
      noResults() {
 | 
			
		||||
@@ -67,11 +86,16 @@ export default {
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
div.custom4,
 | 
			
		||||
div.custom3,
 | 
			
		||||
div.custom2 {
 | 
			
		||||
   font-style: italic;
 | 
			
		||||
   color: var(--bs-chill-gray);
 | 
			
		||||
}
 | 
			
		||||
span.counter {
 | 
			
		||||
   & > span {
 | 
			
		||||
      background-color: unset;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,32 +1,71 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="accompanying_course_work">
 | 
			
		||||
   <div class="alert alert-light">{{ $t('my_evaluations.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">id</th>
 | 
			
		||||
         <th scope="col">{{ $t('max_date') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('evaluation') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('SocialAction') }}</th>
 | 
			
		||||
         <th scope="col"></th>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-slot:tbody>
 | 
			
		||||
         <tr v-for="(e, i) in evaluations.results" :key="`evaluation-${i}`">
 | 
			
		||||
            <td>{{ e.id}}</td>
 | 
			
		||||
            <td>{{ $d(e.maxDate.datetime, 'short') }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <a class="btn btn-sm btn-show" :href="getUrl(e)">
 | 
			
		||||
                  {{ $t('show_entity', { entity: $t('the_evaluation') }) }}
 | 
			
		||||
               </a>
 | 
			
		||||
               {{ e.evaluation.title.fr }}
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <span class="chill-entity entity-social-issue">
 | 
			
		||||
                  <span class="badge bg-chill-l-gray text-dark">
 | 
			
		||||
                     {{ e.accompanyingPeriodWork.socialAction.issue.text }}
 | 
			
		||||
                  </span>
 | 
			
		||||
               </span>
 | 
			
		||||
               <h4 class="badge-title">
 | 
			
		||||
                  <span class="title_label"></span>
 | 
			
		||||
                  <span class="title_action">
 | 
			
		||||
                     {{ e.accompanyingPeriodWork.socialAction.text }}
 | 
			
		||||
                  </span>
 | 
			
		||||
               </h4>
 | 
			
		||||
               <span v-for="person in e.accompanyingPeriodWork.persons" class="me-1" :key="person.id">
 | 
			
		||||
                  <on-the-fly
 | 
			
		||||
                     :type="person.type"
 | 
			
		||||
                     :id="person.id"
 | 
			
		||||
                     :buttonText="person.textAge"
 | 
			
		||||
                     :displayBadge="'true' === 'true'"
 | 
			
		||||
                     action="show">
 | 
			
		||||
                  </on-the-fly>
 | 
			
		||||
               </span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <div class="btn-group-vertical" role="group" aria-label="Actions">
 | 
			
		||||
                  <a class="btn btn-sm btn-show" :href="getUrl(e)">
 | 
			
		||||
                     {{ $t('show_entity', { entity: $t('the_evaluation') }) }}
 | 
			
		||||
                  </a>
 | 
			
		||||
                  <a class="btn btn-sm btn-update" :href="getUrl(e.accompanyingPeriodWork)">
 | 
			
		||||
                     {{ $t('show_entity', { entity: $t('the_action') }) }}
 | 
			
		||||
                  </a>
 | 
			
		||||
                  <a class="btn btn-sm btn-show" :href="getUrl(e.accompanyingPeriodWork.accompanyingPeriod)">
 | 
			
		||||
                     {{ $t('show_entity', { entity: $t('the_course') }) }}
 | 
			
		||||
                  </a>
 | 
			
		||||
               </div>
 | 
			
		||||
            </td>
 | 
			
		||||
         </tr>
 | 
			
		||||
      </template>
 | 
			
		||||
   </tab-table>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import TabTable from "./TabTable";
 | 
			
		||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
   name: "MyEvaluations",
 | 
			
		||||
   components: {
 | 
			
		||||
      TabTable
 | 
			
		||||
      TabTable,
 | 
			
		||||
      OnTheFly,
 | 
			
		||||
   },
 | 
			
		||||
   computed: {
 | 
			
		||||
      ...mapState([
 | 
			
		||||
@@ -45,8 +84,17 @@ export default {
 | 
			
		||||
   },
 | 
			
		||||
   methods: {
 | 
			
		||||
      getUrl(e) {
 | 
			
		||||
         let anchor = '#evaluations';
 | 
			
		||||
         return `/fr/person/accompanying-period/work/${e.id}/edit${anchor}`
 | 
			
		||||
         switch (e.type) {
 | 
			
		||||
            case 'accompanying_period_work_evaluation':
 | 
			
		||||
               let anchor = '#evaluations';
 | 
			
		||||
               return `/fr/person/accompanying-period/work/${e.accompanyingPeriodWork.id}/edit${anchor}`;
 | 
			
		||||
            case 'accompanying_period_work':
 | 
			
		||||
               return `/fr/person/accompanying-period/work/${e.id}/edit`
 | 
			
		||||
            case 'accompanying_period':
 | 
			
		||||
               return `/fr/parcours/${e.id}`
 | 
			
		||||
            default:
 | 
			
		||||
               throw 'entity type unknown';
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
   },
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,8 @@
 | 
			
		||||
                  <a :href="getNotificationUrl(n)">{{ n.title }}</a>
 | 
			
		||||
               </span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>{{ n.sender.text }}</td>
 | 
			
		||||
            <td v-if="n.sender != null">{{ n.sender.text }}</td>
 | 
			
		||||
            <td v-else>{{ $t('automatic_notification')}}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <a class="btn btn-sm btn-show"
 | 
			
		||||
                  :href="getEntityUrl(n)">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,21 @@
 | 
			
		||||
<template>
 | 
			
		||||
   
 | 
			
		||||
   <div class="alert alert-light">{{ $t('my_tasks.description_alert') }}</div>
 | 
			
		||||
   <span v-if="noResultsWarning" class="chill-no-data-statement">{{ $t('no_data') }}</span>
 | 
			
		||||
   <div class="alert alert-light">{{ $t('my_tasks.description_warning') }}</div>
 | 
			
		||||
   <span v-if="noResultsAlert" class="chill-no-data-statement">{{ $t('no_data') }}</span>
 | 
			
		||||
   <tab-table v-else>
 | 
			
		||||
      <template v-slot:thead>
 | 
			
		||||
         <th scope="col">id</th>
 | 
			
		||||
         <th scope="col">{{ $t('warning_date') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('max_date') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('task') }}</th>
 | 
			
		||||
         <th scope="col"></th>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-slot:tbody>
 | 
			
		||||
         <tr v-for="(t, i) in tasks.warning" :key="`task-warning-${i}`">
 | 
			
		||||
            <td>{{ t.id}}</td>
 | 
			
		||||
         <tr v-for="(t, i) in tasks.alert.results" :key="`task-alert-${i}`">
 | 
			
		||||
            <td>{{ $d(t.warningDate.datetime, 'short') }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <span class="outdated">{{ $d(t.endDate.datetime, 'short') }}</span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>{{ t.title }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <a class="btn btn-sm btn-show" :href="getUrl(t)">
 | 
			
		||||
                  {{ $t('show_entity', { entity: $t('the_task') }) }}
 | 
			
		||||
@@ -19,16 +25,22 @@
 | 
			
		||||
      </template>
 | 
			
		||||
   </tab-table>
 | 
			
		||||
   
 | 
			
		||||
   <div class="alert alert-light">{{ $t('my_tasks.description_warning') }}</div>
 | 
			
		||||
   <span v-if="noResultsAlert" class="chill-no-data-statement">{{ $t('no_data') }}</span>
 | 
			
		||||
   <div class="alert alert-light">{{ $t('my_tasks.description_alert') }}</div>
 | 
			
		||||
   <span v-if="noResultsWarning" class="chill-no-data-statement">{{ $t('no_data') }}</span>
 | 
			
		||||
   <tab-table v-else>
 | 
			
		||||
      <template v-slot:thead>
 | 
			
		||||
         <th scope="col">id</th>
 | 
			
		||||
         <th scope="col">{{ $t('warning_date') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('max_date') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('task') }}</th>
 | 
			
		||||
         <th scope="col"></th>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-slot:tbody>
 | 
			
		||||
         <tr v-for="(t, i) in tasks.alert" :key="`task-alert-${i}`">
 | 
			
		||||
            <td>{{ t.id}}</td>
 | 
			
		||||
         <tr v-for="(t, i) in tasks.warning.results" :key="`task-warning-${i}`">
 | 
			
		||||
            <td>
 | 
			
		||||
               <span class="outdated">{{ $d(t.warningDate.datetime, 'short') }}</span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>{{ $d(t.endDate.datetime, 'short') }}</td>
 | 
			
		||||
            <td>{{ t.title }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <a class="btn btn-sm btn-show" :href="getUrl(t)">
 | 
			
		||||
                  {{ $t('show_entity', { entity: $t('the_task') }) }}
 | 
			
		||||
@@ -81,5 +93,8 @@ export default {
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
 | 
			
		||||
span.outdated {
 | 
			
		||||
   font-weight: bold;
 | 
			
		||||
   color: var(--bs-warning);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -6,12 +6,18 @@
 | 
			
		||||
      <template v-slot:thead>
 | 
			
		||||
         <th scope="col">{{ $t('StartDate') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('SocialAction') }}</th>
 | 
			
		||||
         <th scope="col">{{ $t('concerned_persons') }}</th>
 | 
			
		||||
         <th scope="col"></th>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-slot:tbody>
 | 
			
		||||
         <tr v-for="(w, i) in works.results" :key="`works-${i}`">
 | 
			
		||||
            <td>{{ $d(w.startDate.datetime, 'short') }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <span class="chill-entity entity-social-issue">
 | 
			
		||||
                  <span class="badge bg-chill-l-gray text-dark">
 | 
			
		||||
                     {{ w.socialAction.issue.text }}
 | 
			
		||||
                  </span>
 | 
			
		||||
               </span>
 | 
			
		||||
               <h4 class="badge-title">
 | 
			
		||||
                  <span class="title_label"></span>
 | 
			
		||||
                  <span class="title_action">
 | 
			
		||||
@@ -20,7 +26,18 @@
 | 
			
		||||
               </h4>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <div class="btn-group" role="group" aria-label="Actions">
 | 
			
		||||
               <span v-for="person in w.persons" class="me-1" :key="person.id">
 | 
			
		||||
                  <on-the-fly
 | 
			
		||||
                     :type="person.type"
 | 
			
		||||
                     :id="person.id"
 | 
			
		||||
                     :buttonText="person.textAge"
 | 
			
		||||
                     :displayBadge="'true' === 'true'"
 | 
			
		||||
                     action="show">
 | 
			
		||||
                  </on-the-fly>
 | 
			
		||||
               </span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
               <div class="btn-group-vertical" role="group" aria-label="Actions">
 | 
			
		||||
                  <a class="btn btn-sm btn-update" :href="getUrl(w)">
 | 
			
		||||
                     {{ $t('show_entity', { entity: $t('the_action') }) }}
 | 
			
		||||
                  </a>
 | 
			
		||||
@@ -38,11 +55,13 @@
 | 
			
		||||
<script>
 | 
			
		||||
import { mapState, mapGetters } from "vuex";
 | 
			
		||||
import TabTable from "./TabTable";
 | 
			
		||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
   name: "MyWorks",
 | 
			
		||||
   components: {
 | 
			
		||||
      TabTable
 | 
			
		||||
      TabTable,
 | 
			
		||||
      OnTheFly,
 | 
			
		||||
   },
 | 
			
		||||
   computed: {
 | 
			
		||||
      ...mapState([
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
   <span v-if="isCounterAvailable"
 | 
			
		||||
         class="badge rounded-pill bg-danger counter">
 | 
			
		||||
         class="badge rounded-pill bg-danger">
 | 
			
		||||
      {{ count }}
 | 
			
		||||
   </span>
 | 
			
		||||
</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,15 @@ const appMessages = {
 | 
			
		||||
            tab: "Mes notifications",
 | 
			
		||||
            description: "Liste des notifications reçues et non lues.",
 | 
			
		||||
        },
 | 
			
		||||
        opening_date: "Date d'ouverture",
 | 
			
		||||
        social_issues: "Problématiques sociales",
 | 
			
		||||
        concerned_persons: "Usagers concernés",
 | 
			
		||||
        max_date: "Date d'échéance",
 | 
			
		||||
        warning_date: "Date de rappel",
 | 
			
		||||
        evaluation: "Évaluation",
 | 
			
		||||
        task: "Tâche",
 | 
			
		||||
        Date: "Date",
 | 
			
		||||
        From: "De",
 | 
			
		||||
        From: "Expéditeur",
 | 
			
		||||
        Subject: "Objet",
 | 
			
		||||
        Entity: "Associé à",
 | 
			
		||||
        show_entity: "Voir {entity}",
 | 
			
		||||
@@ -37,13 +44,16 @@ const appMessages = {
 | 
			
		||||
        no_data: "Aucun résultats",
 | 
			
		||||
        no_dashboard: "Pas de tableaux de bord",
 | 
			
		||||
        counter: {
 | 
			
		||||
            unread_notifications: "notifications non lues",
 | 
			
		||||
            assignated_courses: "parcours récents assignés",
 | 
			
		||||
            assignated_actions: "actions assignées",
 | 
			
		||||
            assignated_evaluations: "évaluations assignées",
 | 
			
		||||
            alert_tasks: "tâches en rappel",
 | 
			
		||||
            warning_tasks: "tâches à échéances",
 | 
			
		||||
        }
 | 
			
		||||
            unread_notifications: "{n} notification non lue | {n} notifications non lues",
 | 
			
		||||
            assignated_courses: "{n} parcours récent assigné | {n} parcours récents assignés",
 | 
			
		||||
            assignated_actions: "{n} action assignée | {n} actions assignées",
 | 
			
		||||
            assignated_evaluations: "{n} évaluation assignée | {n} évaluations assignées",
 | 
			
		||||
            alert_tasks: "{n} tâche en rappel | {n} tâches en rappel",
 | 
			
		||||
            warning_tasks: "{n} tâche à échéance | {n} tâches à échéance",
 | 
			
		||||
        },
 | 
			
		||||
        emergency: "Urgent",
 | 
			
		||||
        confidential: "Confidentiel",
 | 
			
		||||
        automatic_notification: "Notification automatique"
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -62,27 +62,27 @@ const store = createStore({
 | 
			
		||||
    },
 | 
			
		||||
    mutations: {
 | 
			
		||||
        addWorks(state, works) {
 | 
			
		||||
            console.log('addWorks', works);
 | 
			
		||||
            //console.log('addWorks', works);
 | 
			
		||||
            state.works = works;
 | 
			
		||||
        },
 | 
			
		||||
        addEvaluations(state, evaluations) {
 | 
			
		||||
            console.log('addEvaluations', evaluations);
 | 
			
		||||
            //console.log('addEvaluations', evaluations);
 | 
			
		||||
            state.evaluations = evaluations;
 | 
			
		||||
        },
 | 
			
		||||
        addTasksWarning(state, tasks) {
 | 
			
		||||
            console.log('addTasksWarning', tasks);
 | 
			
		||||
            //console.log('addTasksWarning', tasks);
 | 
			
		||||
            state.tasks.warning = tasks;
 | 
			
		||||
        },
 | 
			
		||||
        addTasksAlert(state, tasks) {
 | 
			
		||||
            console.log('addTasksAlert', tasks);
 | 
			
		||||
            //console.log('addTasksAlert', tasks);
 | 
			
		||||
            state.tasks.alert = tasks;
 | 
			
		||||
        },
 | 
			
		||||
        addCourses(state, courses) {
 | 
			
		||||
            console.log('addCourses', courses);
 | 
			
		||||
            //console.log('addCourses', courses);
 | 
			
		||||
            state.accompanyingCourses = courses;
 | 
			
		||||
        },
 | 
			
		||||
        addNotifications(state, notifications) {
 | 
			
		||||
            console.log('addNotifications', notifications);
 | 
			
		||||
            //console.log('addNotifications', notifications);
 | 
			
		||||
            state.notifications = notifications;
 | 
			
		||||
        },
 | 
			
		||||
        setLoading(state, bool) {
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ export default {
 | 
			
		||||
      OnTheFlyThirdparty,
 | 
			
		||||
      OnTheFlyCreate
 | 
			
		||||
   },
 | 
			
		||||
   props: ['type', 'id', 'action', 'buttonText', 'displayBadge', 'isDead', 'parent', 'canCloseModal'],
 | 
			
		||||
   props: ['type', 'id', 'action', 'buttonText', 'displayBadge', 'isDead', 'parent'],
 | 
			
		||||
   emits: ['saveFormOnTheFly'],
 | 
			
		||||
   data() {
 | 
			
		||||
      return {
 | 
			
		||||
@@ -160,17 +160,10 @@ export default {
 | 
			
		||||
      },
 | 
			
		||||
      badgeType() {
 | 
			
		||||
         return 'entity-' + this.type + ' badge-' + this.type;
 | 
			
		||||
      }
 | 
			
		||||
   },
 | 
			
		||||
   watch: {
 | 
			
		||||
      canCloseModal: {
 | 
			
		||||
         handler: function(val, oldVal) {
 | 
			
		||||
            if (val) {
 | 
			
		||||
               this.closeModal();
 | 
			
		||||
            }
 | 
			
		||||
         },
 | 
			
		||||
         deep: true
 | 
			
		||||
      }
 | 
			
		||||
      },
 | 
			
		||||
      getReturnPath() {
 | 
			
		||||
         return `?returnPath=${window.location.pathname}${window.location.search}${window.location.hash}`;
 | 
			
		||||
      },
 | 
			
		||||
   },
 | 
			
		||||
   methods: {
 | 
			
		||||
      closeModal() {
 | 
			
		||||
@@ -217,9 +210,9 @@ export default {
 | 
			
		||||
      buildLocation(id, type) {
 | 
			
		||||
         if (type === 'person') {
 | 
			
		||||
            // TODO i18n
 | 
			
		||||
            return `/fr/person/${id}/general`;
 | 
			
		||||
            return encodeURI(`/fr/person/${id}/general${this.getReturnPath}`);
 | 
			
		||||
         } else if (type === 'thirdparty') {
 | 
			
		||||
            return `/fr/3party/3party/${id}/view`;
 | 
			
		||||
            return encodeURI(`/fr/3party/3party/${id}/view${this.getReturnPath}`);
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
        </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
    <ul class="record_actions">
 | 
			
		||||
        <li>
 | 
			
		||||
            <AddPersons
 | 
			
		||||
        <li class="add-persons">
 | 
			
		||||
            <add-persons
 | 
			
		||||
                :options="addPersonsOptions"
 | 
			
		||||
                :key="uniqid"
 | 
			
		||||
                :buttonTitle="translatedListOfTypes"
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
                ref="addPersons"
 | 
			
		||||
                @addNewPersons="addNewEntity"
 | 
			
		||||
            >
 | 
			
		||||
            </AddPersons>
 | 
			
		||||
            </add-persons>
 | 
			
		||||
        </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,7 @@
 | 
			
		||||
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n';
 | 
			
		||||
import { thirdpartyMessages } from 'ChillThirdPartyAssets/vuejs/_js/i18n';
 | 
			
		||||
import { addressMessages } from 'ChillMainAssets/vuejs/Address/i18n';
 | 
			
		||||
import { ontheflyMessages } from 'ChillMainAssets/vuejs/OnTheFly/i18n';
 | 
			
		||||
 | 
			
		||||
const appMessages = {
 | 
			
		||||
    fr: {
 | 
			
		||||
@@ -12,6 +15,6 @@ const appMessages = {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object.assign(appMessages.fr, personMessages.fr);
 | 
			
		||||
Object.assign(appMessages.fr, personMessages.fr, thirdpartyMessages.fr, addressMessages.fr, ontheflyMessages.fr );
 | 
			
		||||
 | 
			
		||||
export { appMessages };
 | 
			
		||||
 
 | 
			
		||||
@@ -42,57 +42,11 @@
 | 
			
		||||
                  class="street">
 | 
			
		||||
                  {{ address.text }}
 | 
			
		||||
               </p>
 | 
			
		||||
               <p v-if="address.postcode"
 | 
			
		||||
                  class="postcode">
 | 
			
		||||
                  {{ address.postcode.code }} {{ address.postcode.name }}
 | 
			
		||||
               </p>
 | 
			
		||||
               <p v-if="address.country"
 | 
			
		||||
                  class="country">
 | 
			
		||||
                  {{ address.country.name.fr }}
 | 
			
		||||
               </p>
 | 
			
		||||
            </div>
 | 
			
		||||
         </div>
 | 
			
		||||
 | 
			
		||||
      </component>
 | 
			
		||||
 | 
			
		||||
      <!-- <div v-if="isMultiline === true" class="address-more">
 | 
			
		||||
         <div v-if="address.floor">
 | 
			
		||||
            <span class="floor">
 | 
			
		||||
               <b>{{ $t('floor') }}</b>: {{ address.floor }}
 | 
			
		||||
            </span>
 | 
			
		||||
         </div>
 | 
			
		||||
         <div v-if="address.corridor">
 | 
			
		||||
            <span class="corridor">
 | 
			
		||||
               <b>{{ $t('corridor') }}</b>: {{ address.corridor }}
 | 
			
		||||
            </span>
 | 
			
		||||
         </div>
 | 
			
		||||
         <div v-if="address.steps">
 | 
			
		||||
            <span class="steps">
 | 
			
		||||
               <b>{{ $t('steps') }}</b>: {{ address.steps }}
 | 
			
		||||
            </span>
 | 
			
		||||
         </div>
 | 
			
		||||
         <div v-if="address.flat">
 | 
			
		||||
            <span class="flat">
 | 
			
		||||
               <b>{{ $t('flat') }}</b>: {{ address.flat }}
 | 
			
		||||
            </span>
 | 
			
		||||
         </div>
 | 
			
		||||
         <div v-if="address.buildingName">
 | 
			
		||||
               <span class="buildingName">
 | 
			
		||||
                  <b>{{ $t('buildingName') }}</b>: {{ address.buildingName }}
 | 
			
		||||
               </span>
 | 
			
		||||
         </div>
 | 
			
		||||
         <div v-if="address.extra">
 | 
			
		||||
               <span class="extra">
 | 
			
		||||
                  <b>{{ $t('extra') }}</b>: {{ address.extra }}
 | 
			
		||||
               </span>
 | 
			
		||||
         </div>
 | 
			
		||||
         <div v-if="address.distribution">
 | 
			
		||||
               <span class="distribution">
 | 
			
		||||
                  <b>{{ $t('distribution') }}</b>: {{ address.distribution }}
 | 
			
		||||
               </span>
 | 
			
		||||
         </div>
 | 
			
		||||
      </div> -->
 | 
			
		||||
 | 
			
		||||
      <div v-if="useDatePane === true" class="address-more">
 | 
			
		||||
         <div v-if="address.validFrom">
 | 
			
		||||
            <span class="validFrom">
 | 
			
		||||
 
 | 
			
		||||
@@ -93,8 +93,9 @@ export default {
 | 
			
		||||
      },
 | 
			
		||||
      getPopTitle(step) {
 | 
			
		||||
         if (step.transitionPrevious != null) {
 | 
			
		||||
            //console.log(step.transitionPrevious.text);
 | 
			
		||||
            let freezed = step.isFreezed ? `<i class="fa fa-snowflake-o fa-sm me-1"></i>` : ``;
 | 
			
		||||
            return `${freezed}${step.currentStep.text}`;
 | 
			
		||||
            return `${freezed}${step.transitionPrevious.text}`;
 | 
			
		||||
         }
 | 
			
		||||
      },
 | 
			
		||||
      getPopContent(step) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
   <button v-if="hasWorkflow"
 | 
			
		||||
      class="btn btn-primary"
 | 
			
		||||
      @click="openModal">
 | 
			
		||||
@@ -7,36 +7,39 @@
 | 
			
		||||
      <template v-if="countWorkflows > 1">{{ $t('workflows') }}</template>
 | 
			
		||||
      <template v-else>{{ $t('workflow') }}</template>
 | 
			
		||||
   </button>
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
   <pick-workflow v-else-if="allowCreate"
 | 
			
		||||
      :relatedEntityClass="this.relatedEntityClass"
 | 
			
		||||
      :relatedEntityId="this.relatedEntityId"
 | 
			
		||||
      :workflowsAvailables="workflowsAvailables"
 | 
			
		||||
      @go-to-generate-workflow="goToGenerateWorkflow"
 | 
			
		||||
   ></pick-workflow>
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
   <teleport to="body">
 | 
			
		||||
      <modal v-if="modal.showModal"
 | 
			
		||||
         :modalDialogClass="modal.modalDialogClass"
 | 
			
		||||
         @close="modal.showModal = false">
 | 
			
		||||
         
 | 
			
		||||
 | 
			
		||||
         <template v-slot:header>
 | 
			
		||||
            <h2 class="modal-title">{{ $t('workflow_list') }}</h2>
 | 
			
		||||
         </template>
 | 
			
		||||
         
 | 
			
		||||
 | 
			
		||||
         <template v-slot:body>
 | 
			
		||||
            <list-workflow-vue
 | 
			
		||||
               :workflows="workflows"
 | 
			
		||||
            ></list-workflow-vue>
 | 
			
		||||
         </template>
 | 
			
		||||
         
 | 
			
		||||
 | 
			
		||||
         <template v-slot:footer>
 | 
			
		||||
            <pick-workflow v-if="allowCreate"
 | 
			
		||||
               :relatedEntityClass="this.relatedEntityClass"
 | 
			
		||||
               :relatedEntityId="this.relatedEntityId"
 | 
			
		||||
               :workflowsAvailables="workflowsAvailables"
 | 
			
		||||
               :preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
 | 
			
		||||
               @go-to-generate-workflow="this.goToGenerateWorkflow"
 | 
			
		||||
            ></pick-workflow>
 | 
			
		||||
         </template>
 | 
			
		||||
         
 | 
			
		||||
 | 
			
		||||
      </modal>
 | 
			
		||||
   </teleport>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -53,6 +56,7 @@ export default {
 | 
			
		||||
      PickWorkflow,
 | 
			
		||||
      ListWorkflowVue
 | 
			
		||||
   },
 | 
			
		||||
   emits: ['goToGenerateWorkflow'],
 | 
			
		||||
   props: {
 | 
			
		||||
      workflows: {
 | 
			
		||||
         type: Array,
 | 
			
		||||
@@ -73,9 +77,14 @@ export default {
 | 
			
		||||
      workflowsAvailables: {
 | 
			
		||||
         type: Array,
 | 
			
		||||
         required: true,
 | 
			
		||||
      }
 | 
			
		||||
      },
 | 
			
		||||
      preventDefaultMoveToGenerate: {
 | 
			
		||||
          type: Boolean,
 | 
			
		||||
          required: false,
 | 
			
		||||
          default: false,
 | 
			
		||||
      },
 | 
			
		||||
   },
 | 
			
		||||
   data() {
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
         modal: {
 | 
			
		||||
            showModal: false,
 | 
			
		||||
@@ -95,6 +104,10 @@ export default {
 | 
			
		||||
      openModal() {
 | 
			
		||||
         this.modal.showModal = true;
 | 
			
		||||
      },
 | 
			
		||||
      goToGenerateWorkflow(data) {
 | 
			
		||||
          console.log('go to generate workflow intercepted');
 | 
			
		||||
          this.$emit('goToGenerateWorkflow', data);
 | 
			
		||||
      }
 | 
			
		||||
   },
 | 
			
		||||
   i18n: {
 | 
			
		||||
      messages: {
 | 
			
		||||
@@ -108,4 +121,4 @@ export default {
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
            </button>
 | 
			
		||||
            <ul class="dropdown-menu" aria-labelledby="createWorkflowButton">
 | 
			
		||||
                <li v-for="w in workflowsAvailables" :key="w.name">
 | 
			
		||||
                    <a class="dropdown-item" :href="makeLink(w.name)" @click="goToGenerateWorkflow($event, w.name)">{{ w.text }}</a>
 | 
			
		||||
                    <a class="dropdown-item" :href="makeLink(w.name)" @click.prevent="goToGenerateWorkflow($event, w.name)">{{ w.text }}</a>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -31,7 +31,12 @@ export default {
 | 
			
		||||
        workflowsAvailables: {
 | 
			
		||||
            type: Array,
 | 
			
		||||
            required: true,
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
        preventDefaultMoveToGenerate: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
            required: false,
 | 
			
		||||
            default: false,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    emits: ['goToGenerateWorkflow'],
 | 
			
		||||
    methods: {
 | 
			
		||||
@@ -39,6 +44,13 @@ export default {
 | 
			
		||||
            return buildLinkCreate(workflowName, this.relatedEntityClass, this.relatedEntityId);
 | 
			
		||||
        },
 | 
			
		||||
        goToGenerateWorkflow(event, workflowName) {
 | 
			
		||||
            console.log('goToGenerateWorkflow', event, workflowName);
 | 
			
		||||
 | 
			
		||||
            if (!this.$props.preventDefaultMoveToGenerate) {
 | 
			
		||||
                console.log('to go generate');
 | 
			
		||||
                window.location.assign(this.makeLink(workflowName));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.$emit('goToGenerateWorkflow', {event, workflowName, link: this.makeLink(workflowName)});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
<template>
 | 
			
		||||
   <a v-if="isOpenDocument"
 | 
			
		||||
      class="btn change-icon" :class="[isChangeClass ? button.changeClass : 'btn-edit']"
 | 
			
		||||
      class="btn" :class="[
 | 
			
		||||
         isChangeIcon ? 'change-icon' : '',
 | 
			
		||||
         isChangeClass ? options.changeClass : 'btn-wopilink' ]"
 | 
			
		||||
      @click="openModal">
 | 
			
		||||
      
 | 
			
		||||
      <i class="fa me-2" :class="[isChangeIcon ? button.changeIcon : 'fa-pencil']"></i>
 | 
			
		||||
      <i v-if="isChangeIcon" class="fa me-2" :class="options.changeIcon"></i>
 | 
			
		||||
      
 | 
			
		||||
      <span v-if="!noText">
 | 
			
		||||
         {{ $t('Update_document') }}
 | 
			
		||||
         {{ $t('online_edit_document') }}
 | 
			
		||||
      </span>
 | 
			
		||||
   </a>
 | 
			
		||||
   
 | 
			
		||||
@@ -20,12 +22,14 @@
 | 
			
		||||
            <template v-slot:header>
 | 
			
		||||
               <img class="logo" :src="logo" height="45"/>
 | 
			
		||||
                  <span class="ms-auto me-3">
 | 
			
		||||
                     {{ this.title }}
 | 
			
		||||
                     <span v-if="options.title">{{ options.title }}</span>
 | 
			
		||||
                  </span>
 | 
			
		||||
                  <!--
 | 
			
		||||
                  <a class="btn btn-outline-light">
 | 
			
		||||
                     <i class="fa fa-save fa-fw"></i>
 | 
			
		||||
                     {{ $t('save_and_quit') }}
 | 
			
		||||
                  </a>
 | 
			
		||||
                  -->
 | 
			
		||||
            </template>
 | 
			
		||||
            
 | 
			
		||||
            <template v-slot:body>
 | 
			
		||||
@@ -71,15 +75,11 @@ export default {
 | 
			
		||||
         type: String,
 | 
			
		||||
         required: true
 | 
			
		||||
      },
 | 
			
		||||
      title: {
 | 
			
		||||
         type: String,
 | 
			
		||||
         required: true
 | 
			
		||||
      },
 | 
			
		||||
      type: {
 | 
			
		||||
         type: String,
 | 
			
		||||
         required: true
 | 
			
		||||
      },
 | 
			
		||||
      button: {
 | 
			
		||||
      options: {
 | 
			
		||||
         type: Object,
 | 
			
		||||
         required: false
 | 
			
		||||
      }
 | 
			
		||||
@@ -175,20 +175,20 @@ export default {
 | 
			
		||||
         return false;
 | 
			
		||||
      },
 | 
			
		||||
      noText() {
 | 
			
		||||
         if (typeof this.button.noText !== 'undefined') {
 | 
			
		||||
            return this.button.noText === true;
 | 
			
		||||
         if (typeof this.options.noText !== 'undefined') {
 | 
			
		||||
            return this.options.noText === true;
 | 
			
		||||
         }
 | 
			
		||||
         return false;
 | 
			
		||||
      },
 | 
			
		||||
      isChangeIcon() {
 | 
			
		||||
         if (typeof this.button.changeIcon !== 'undefined') {
 | 
			
		||||
            return (!(this.button.changeIcon === null || this.button.changeIcon === ''))
 | 
			
		||||
         if (typeof this.options.changeIcon !== 'undefined') {
 | 
			
		||||
            return (!(this.options.changeIcon === null || this.options.changeIcon === ''))
 | 
			
		||||
         }
 | 
			
		||||
         return false;
 | 
			
		||||
      },
 | 
			
		||||
      isChangeClass() {
 | 
			
		||||
         if (typeof this.button.changeClass !== 'undefined') {
 | 
			
		||||
            return (!(this.button.changeClass === null || this.button.changeClass === ''))
 | 
			
		||||
         if (typeof this.options.changeClass !== 'undefined') {
 | 
			
		||||
            return (!(this.options.changeClass === null || this.options.changeClass === ''))
 | 
			
		||||
         }
 | 
			
		||||
         return false;
 | 
			
		||||
      }
 | 
			
		||||
@@ -205,7 +205,7 @@ export default {
 | 
			
		||||
   i18n: {
 | 
			
		||||
      messages: {
 | 
			
		||||
         fr: {
 | 
			
		||||
            Update_document: "Modifier le document",
 | 
			
		||||
            online_edit_document: "Éditer en ligne",
 | 
			
		||||
            save_and_quit: "Enregistrer et quitter",
 | 
			
		||||
            loading: "Chargement de l'éditeur en ligne",
 | 
			
		||||
            invalid_title: "Format incompatible",
 | 
			
		||||
 
 | 
			
		||||
@@ -91,11 +91,11 @@ export const multiSelectMessages = {
 | 
			
		||||
    multiselect: {
 | 
			
		||||
      placeholder: 'Choisir',
 | 
			
		||||
      tag_placeholder: 'Créer un nouvel élément',
 | 
			
		||||
      select_label: 'Appuyer sur "Entrée" pour sélectionner',
 | 
			
		||||
      deselect_label: 'Appuyer sur "Entrée" pour désélectionner',
 | 
			
		||||
      select_label: '"Entrée" ou cliquez pour sélectionner',
 | 
			
		||||
      deselect_label: '"Entrée" ou cliquez pour désélectionner',
 | 
			
		||||
      select_group_label: 'Appuyer sur "Entrée" pour sélectionner ce groupe',
 | 
			
		||||
      deselect_group_label: 'Appuyer sur "Entrée" pour désélectionner ce groupe',
 | 
			
		||||
      selected_label: 'Sélectionné'
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,11 @@
 | 
			
		||||
 | 
			
		||||
<div class="notification-comment-list my-5">
 | 
			
		||||
    <h2 class="chill-blue">{{ 'notification.comments_list'|trans }}</h2>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    {% if notification.comments|length > 0 %}
 | 
			
		||||
        <div class="flex-table">
 | 
			
		||||
            {% for comment in notification.comments %}
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                {% if editedCommentForm is null or editedCommentId != comment.id %}
 | 
			
		||||
                    {{ m.show_comment(comment, {
 | 
			
		||||
                        'recordAction': _self.recordAction(comment)
 | 
			
		||||
@@ -28,10 +28,11 @@
 | 
			
		||||
                    <div class="item-bloc">
 | 
			
		||||
                        <div class="item-row row">
 | 
			
		||||
                            <a id="comment-{{ comment.id }}"></a>
 | 
			
		||||
                            
 | 
			
		||||
 | 
			
		||||
                            {{ form_start(editedCommentForm) }}
 | 
			
		||||
                            {{ form_errors(editedCommentForm) }}
 | 
			
		||||
                            {{ form_widget(editedCommentForm.content) }}
 | 
			
		||||
                            {{ form_errors(editedCommentForm.content) }}
 | 
			
		||||
                            <input type="hidden" name="form" value="edit" />
 | 
			
		||||
                            <ul class="record_actions">
 | 
			
		||||
                                <li class="cancel">
 | 
			
		||||
@@ -46,24 +47,25 @@
 | 
			
		||||
                                </li>
 | 
			
		||||
                            </ul>
 | 
			
		||||
                            {{ form_end(editedCommentForm) }}
 | 
			
		||||
                        
 | 
			
		||||
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </div>
 | 
			
		||||
    {% else %}
 | 
			
		||||
        <span class="chill-no-data-statement">{{ 'No comments'|trans }}</span>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    {% if appendCommentForm is not null %}
 | 
			
		||||
        <div class="new-comment my-5">
 | 
			
		||||
            <h2 class="chill-blue mb-4">{{ 'Write a new comment'|trans }}</h2>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            {{ form_start(appendCommentForm) }}
 | 
			
		||||
            {{ form_errors(appendCommentForm) }}
 | 
			
		||||
            {{ form_widget(appendCommentForm.content) }}
 | 
			
		||||
            {{ form_errors(appendCommentForm.content) }}
 | 
			
		||||
            <input type="hidden" name="form" value="append" />
 | 
			
		||||
            <ul class="record_actions">
 | 
			
		||||
                <li>
 | 
			
		||||
@@ -71,7 +73,7 @@
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
            {{ form_end(appendCommentForm) }}
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -72,10 +72,13 @@
 | 
			
		||||
        <div class="item-row separator">
 | 
			
		||||
            <div class="item-col item-meta">
 | 
			
		||||
                
 | 
			
		||||
                {# TODO twig extension to count comments #}
 | 
			
		||||
                <div class="comment-counter visually-hidden">
 | 
			
		||||
                    <span>x commentaires</span>
 | 
			
		||||
                </div>
 | 
			
		||||
                {% if c.notification.comments|length > 0 %}
 | 
			
		||||
                    <div class="comment-counter">
 | 
			
		||||
                        <span class="counter">
 | 
			
		||||
                            {{ 'notification.counter comments'|trans({'nb': c.notification.comments|length }) }}
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="item-col">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
<div class="notification-counter">
 | 
			
		||||
    {% if counter.total > 0 %}
 | 
			
		||||
        <span>
 | 
			
		||||
        <span class="counter">
 | 
			
		||||
            {{ 'notification.counter total notifications'|trans({'total': counter.total }) }}
 | 
			
		||||
        </span>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {% if counter.unread > 0 %}
 | 
			
		||||
        <span>
 | 
			
		||||
        <span class="counter">
 | 
			
		||||
            {{ 'notification.counter unread notifications'|trans({'unread': counter.unread }) }}
 | 
			
		||||
        </span>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@
 | 
			
		||||
    * buttonText    string
 | 
			
		||||
    * displayBadge  boolean (default: false)  replace button by badge, need to define buttonText for content
 | 
			
		||||
    * parent        object  (optional)        pass parent context of the targetEntity (used for course resource comment)
 | 
			
		||||
    * isDead        boolean (default: false)  is the person dead
 | 
			
		||||
 | 
			
		||||
#}
 | 
			
		||||
<span class="onthefly-container"
 | 
			
		||||
@@ -29,10 +28,6 @@
 | 
			
		||||
        data-button-text="{{ buttonText|e('html_attr') }}"
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% if isDead is defined and isDead == 1  %}
 | 
			
		||||
        data-is-dead="true"
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
    {% if displayBadge is defined and displayBadge == 1 %}
 | 
			
		||||
        data-display-badge="true"
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,58 @@
 | 
			
		||||
{% if transition_form is not null %}
 | 
			
		||||
    {{ form_start(transition_form) }}
 | 
			
		||||
 | 
			
		||||
    {{ form_row(transition_form.transition) }}
 | 
			
		||||
    {% set step = entity_workflow.currentStepChained %}
 | 
			
		||||
    {% set labels = workflow_metadata(entity_workflow, 'label', step.currentStep) %}
 | 
			
		||||
    {% set label = labels is null ? step.currentStep : labels|localize_translatable_string %}
 | 
			
		||||
 | 
			
		||||
    <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-sm-12">
 | 
			
		||||
                    {{ 'workflow.Current step'|trans }} :
 | 
			
		||||
                    <span class="badge bg-primary">{{ label }}</span>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {% if step.previous is not null %}
 | 
			
		||||
                {% if step.previous.comment is not empty %}
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-sm-12">
 | 
			
		||||
                            <blockquote class="chill-user-quote">
 | 
			
		||||
                                {{ step.previous.comment|chill_markdown_to_html }}
 | 
			
		||||
                            </blockquote>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <div class="col-sm-12">
 | 
			
		||||
                        {{ 'By'|trans }}
 | 
			
		||||
                        {{ step.previous.transitionBy|chill_entity_render_box }},
 | 
			
		||||
                        {{ step.previous.transitionAt|format_datetime('short', 'short') }}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% else %}
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <div class="col-sm-4">{{ 'workflow.Created by'|trans }}</div>
 | 
			
		||||
                    <div class="col-sm-8">{{ step.entityWorkflow.createdBy|chill_entity_render_box }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <div class="col-sm-4">{{ 'Le'|trans }}</div>
 | 
			
		||||
                    <div class="col-sm-8">{{ step.entityWorkflow.createdAt|format_datetime('short', 'short') }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div id="transitionFilter">
 | 
			
		||||
        {% if transition_form.transitionFilter is defined %}
 | 
			
		||||
            {{ form_row(transition_form.transitionFilter) }}
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div id="transitions">
 | 
			
		||||
        {{ form_row(transition_form.transition) }}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    {% if transition_form.freezeAfter is defined %}
 | 
			
		||||
        {{ form_row(transition_form.freezeAfter) }}
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,18 @@
 | 
			
		||||
                    </blockquote>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            {% if loop.last and step.destUser|length > 0 %}
 | 
			
		||||
                <div class="item-row separator">
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <p><b>{{ 'workflow.Users allowed to apply transition'|trans }} : </b></p>
 | 
			
		||||
                        <ul>
 | 
			
		||||
                            {% for u in step.destUser %}
 | 
			
		||||
                                <li>{{ u|chill_entity_render_box }}</li>
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </ul>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
    <h2>
 | 
			
		||||
        {{ 'workflow_'|trans }}
 | 
			
		||||
    </h2>
 | 
			
		||||
    {% include handler.templateTitle(l.entity_workflow) with handler.templateTitleData(entity_workflow)|merge({
 | 
			
		||||
    {% include handler.templateTitle(entity_workflow) with handler.templateTitleData(entity_workflow)|merge({
 | 
			
		||||
        'description': true,
 | 
			
		||||
        'breadcrumb': true,
 | 
			
		||||
        'add_classes': 'ms-3 h3'
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
 | 
			
		||||
{% block js %}
 | 
			
		||||
    {{ parent() }}
 | 
			
		||||
    
 | 
			
		||||
    {{ encore_entry_script_tags('mod_async_upload') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_pickentity_type') }}
 | 
			
		||||
    {{ encore_entry_script_tags('mod_entity_workflow_subscribe') }}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,23 @@ declare(strict_types=1);
 | 
			
		||||
namespace Chill\MainBundle\Routing\MenuBuilder;
 | 
			
		||||
 | 
			
		||||
use Knp\Menu\MenuItem;
 | 
			
		||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
 | 
			
		||||
 | 
			
		||||
class LocationMenuBuilder implements \Chill\MainBundle\Routing\LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    private AuthorizationCheckerInterface $authorizationChecker;
 | 
			
		||||
 | 
			
		||||
    public function __construct(AuthorizationCheckerInterface $authorizationChecker)
 | 
			
		||||
    {
 | 
			
		||||
        $this->authorizationChecker = $authorizationChecker;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildMenu($menuId, MenuItem $menu, array $parameters)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $menu->addChild('Location type list', [
 | 
			
		||||
            'route' => 'chill_crud_main_location_type_index',
 | 
			
		||||
        ])->setExtras(['order' => 205]);
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,23 @@ declare(strict_types=1);
 | 
			
		||||
namespace Chill\MainBundle\Routing\MenuBuilder;
 | 
			
		||||
 | 
			
		||||
use Knp\Menu\MenuItem;
 | 
			
		||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
 | 
			
		||||
 | 
			
		||||
class PermissionMenuBuilder implements \Chill\MainBundle\Routing\LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    private AuthorizationCheckerInterface $authorizationChecker;
 | 
			
		||||
 | 
			
		||||
    public function __construct(AuthorizationCheckerInterface $authorizationChecker)
 | 
			
		||||
    {
 | 
			
		||||
        $this->authorizationChecker = $authorizationChecker;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildMenu($menuId, MenuItem $menu, array $parameters)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $menu->addChild('Permissions group list', [
 | 
			
		||||
            'route' => 'admin_permissionsgroup',
 | 
			
		||||
        ])->setExtras([
 | 
			
		||||
 
 | 
			
		||||
@@ -15,22 +15,16 @@ use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
 | 
			
		||||
use Knp\Menu\MenuItem;
 | 
			
		||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
 | 
			
		||||
use Symfony\Component\Translation\TranslatorInterface;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class SectionMenuBuilder.
 | 
			
		||||
 */
 | 
			
		||||
class SectionMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var AuthorizationCheckerInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $authorizationChecker;
 | 
			
		||||
    protected AuthorizationCheckerInterface $authorizationChecker;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TranslatorInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $translator;
 | 
			
		||||
    protected TranslatorInterface $translator;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SectionMenuBuilder constructor.
 | 
			
		||||
@@ -46,22 +40,24 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
     */
 | 
			
		||||
    public function buildMenu($menuId, MenuItem $menu, array $parameters)
 | 
			
		||||
    {
 | 
			
		||||
        $menu->addChild($this->translator->trans('Homepage'), [
 | 
			
		||||
            'route' => 'chill_main_homepage',
 | 
			
		||||
        ])
 | 
			
		||||
            ->setExtras([
 | 
			
		||||
                'icons' => ['home'],
 | 
			
		||||
                'order' => 0,
 | 
			
		||||
            ]);
 | 
			
		||||
        if (!$this->authorizationChecker->isGranted('ROLE_USER')) {
 | 
			
		||||
            $menu->addChild($this->translator->trans('Homepage'), [
 | 
			
		||||
                'route' => 'chill_main_homepage',
 | 
			
		||||
            ])
 | 
			
		||||
                ->setExtras([
 | 
			
		||||
                    'icons' => ['home'],
 | 
			
		||||
                    'order' => 0,
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
        $menu->addChild($this->translator->trans('Global timeline'), [
 | 
			
		||||
            'route' => 'chill_center_timeline',
 | 
			
		||||
        ])
 | 
			
		||||
            ->setExtras(
 | 
			
		||||
                [
 | 
			
		||||
                    'order' => 10,
 | 
			
		||||
                ]
 | 
			
		||||
            );
 | 
			
		||||
            $menu->addChild($this->translator->trans('Global timeline'), [
 | 
			
		||||
                'route' => 'chill_center_timeline',
 | 
			
		||||
            ])
 | 
			
		||||
                ->setExtras(
 | 
			
		||||
                    [
 | 
			
		||||
                        'order' => 10,
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->authorizationChecker->isGranted(ChillExportVoter::EXPORT)) {
 | 
			
		||||
            $menu->addChild($this->translator->trans('Export Menu'), [
 | 
			
		||||
 
 | 
			
		||||
@@ -14,29 +14,43 @@ namespace Chill\MainBundle\Routing\MenuBuilder;
 | 
			
		||||
use Chill\MainBundle\Entity\User;
 | 
			
		||||
use Chill\MainBundle\Notification\Counter\NotificationByUserCounter;
 | 
			
		||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
 | 
			
		||||
use Chill\MainBundle\Workflow\Counter\WorkflowByUserCounter;
 | 
			
		||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
 | 
			
		||||
use Symfony\Component\Security\Core\Security;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
 | 
			
		||||
class UserMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
{
 | 
			
		||||
    private AuthorizationCheckerInterface $authorizationChecker;
 | 
			
		||||
 | 
			
		||||
    private NotificationByUserCounter $notificationByUserCounter;
 | 
			
		||||
 | 
			
		||||
    private Security $security;
 | 
			
		||||
 | 
			
		||||
    private TranslatorInterface $translator;
 | 
			
		||||
 | 
			
		||||
    private WorkflowByUserCounter $workflowByUserCounter;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        NotificationByUserCounter $notificationByUserCounter,
 | 
			
		||||
        WorkflowByUserCounter $workflowByUserCounter,
 | 
			
		||||
        Security $security,
 | 
			
		||||
        TranslatorInterface $translator
 | 
			
		||||
        TranslatorInterface $translator,
 | 
			
		||||
        AuthorizationCheckerInterface $authorizationChecker
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->notificationByUserCounter = $notificationByUserCounter;
 | 
			
		||||
        $this->workflowByUserCounter = $workflowByUserCounter;
 | 
			
		||||
        $this->security = $security;
 | 
			
		||||
        $this->translator = $translator;
 | 
			
		||||
        $this->authorizationChecker = $authorizationChecker;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$this->authorizationChecker->isGranted('ROLE_USER')) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $user = $this->security->getUser();
 | 
			
		||||
 | 
			
		||||
        if ($user instanceof User) {
 | 
			
		||||
@@ -69,9 +83,11 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
 | 
			
		||||
                    'counter' => $nbNotifications,
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
            $workflowCount = $this->workflowByUserCounter->getCountUnreadByUser($user);
 | 
			
		||||
 | 
			
		||||
            $menu
 | 
			
		||||
                ->addChild(
 | 
			
		||||
                    $this->translator->trans('workflow.My workflows'),
 | 
			
		||||
                    $this->translator->trans('workflow.My workflows with counter', ['wc' => $workflowCount]),
 | 
			
		||||
                    ['route' => 'chill_main_workflow_list_dest']
 | 
			
		||||
                )
 | 
			
		||||
                ->setExtras([
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw
 | 
			
		||||
        if ($address instanceof Address) {
 | 
			
		||||
            $data = [
 | 
			
		||||
                'address_id' => $address->getId(),
 | 
			
		||||
                'text' => $address->isNoAddress() ? null : $this->addressRender->renderStreetLine($address, []),
 | 
			
		||||
                'text' => $this->addressRender->renderString($address, []),
 | 
			
		||||
                'street' => $address->getStreet(),
 | 
			
		||||
                'streetNumber' => $address->getStreetNumber(),
 | 
			
		||||
                'postcode' => [
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ declare(strict_types=1);
 | 
			
		||||
namespace Chill\MainBundle\Serializer\Normalizer;
 | 
			
		||||
 | 
			
		||||
use LogicException;
 | 
			
		||||
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
 | 
			
		||||
use Symfony\Component\Serializer\Exception\RuntimeException;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
 | 
			
		||||
@@ -44,7 +45,7 @@ class DiscriminatedObjectDenormalizer implements ContextAwareDenormalizerInterfa
 | 
			
		||||
            if ($this->denormalizer->supportsDenormalization($data, $localType, $format)) {
 | 
			
		||||
                try {
 | 
			
		||||
                    return $this->denormalizer->denormalize($data, $localType, $format, $context);
 | 
			
		||||
                } catch (RuntimeException $e) {
 | 
			
		||||
                } catch (RuntimeException|NotNormalizableValueException $e) {
 | 
			
		||||
                    $lastException = $e;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,6 @@ class NotificationNormalizer implements NormalizerAwareInterface, NormalizerInte
 | 
			
		||||
     */
 | 
			
		||||
    public function normalize($object, ?string $format = null, array $context = [])
 | 
			
		||||
    {
 | 
			
		||||
        dump($object);
 | 
			
		||||
        $entity = $this->entityManager
 | 
			
		||||
            ->getRepository($object->getRelatedEntityClass())
 | 
			
		||||
            ->find($object->getRelatedEntityId());
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,7 @@ class AddressRender implements ChillEntityRenderInterface
 | 
			
		||||
     */
 | 
			
		||||
    public function renderString($addr, array $options): string
 | 
			
		||||
    {
 | 
			
		||||
        return implode(' - ', $this->renderLines($addr));
 | 
			
		||||
        return implode(' — ', $this->renderLines($addr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function supports($entity, array $options): bool
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user