Compare commits

..

73 Commits

Author SHA1 Message Date
76d3612d33 Refactor ChillDocumentLockManager to use database locks and add related tests
- Replaced Redis-based locking mechanism with database-based `StoredObjectLock` management using `EntityManagerInterface`.
- Integrated `MockClock` and `Security` components for lock timing and user association.
- Updated test cases to include database persistence and user assignment during lock operations.
- Implemented `onKernelTerminate` event listener to handle deferred database flush for lock updates.
2026-03-31 21:04:05 +02:00
277e4fa490 Add RandomUserTrait to retrieve random user for testing
- Implemented `getRandomUser` method to fetch a random user using `EntityManagerInterface`.
- Added support for random user retrieval by querying `User` entity repository.
2026-03-31 17:32:36 +02:00
fe11780ad5 Add method to check lock activity and corresponding tests
- Added `isActiveAt` method in `StoredObjectLock` to check if a lock is active at a specific time.
- Implemented `isLockedAt` method in `StoredObject` to determine if an object is locked at a given time.
- Included unit tests for `isActiveAt` method in `StoredObjectLockTest` to validate various scenarios.
2026-03-31 17:32:24 +02:00
c1e5346ef9 Add locking mechanism for stored objects
- Created `StoredObjectLock` entity to manage locks on stored objects.
- Introduced `StoredObjectLockMethodEnum` to define locking methods.
- Added relationships between `StoredObject` and `StoredObjectLock` with appropriate methods for management.
- Added database migrations to create necessary tables and constraints for lock handling.
2026-03-31 14:50:35 +02:00
297628d06f Merge branch 'add-group-center-repository-interface' into 'master'
Create interface GroupCenterRepositoryInterface

See merge request Chill-Projet/chill-bundles!978
2026-03-25 13:41:05 +00:00
3bc12a5469 Create interface GroupCenterRepositoryInterface 2026-03-25 13:41:03 +00:00
300547ad14 Merge branch '507-external-id-center' into 'master'
Resolve "Ajout d'un champ "externalId" pour les centres"

Closes #507

See merge request Chill-Projet/chill-bundles!977
2026-03-24 15:41:31 +00:00
dcccbb36f4 Resolve "Ajout d'un champ "externalId" pour les centres" 2026-03-24 15:41:31 +00:00
d1fe1be0f8 Merge branch 'feature/interesting-release-note-changie' into 'master'
Add IRN field to Changie configuration for release note tagging

See merge request Chill-Projet/chill-bundles!976
2026-03-24 14:45:00 +00:00
6654bea48f Add IRN field to Changie configuration for release note tagging 2026-03-24 14:45:00 +00:00
eb2dfc8591 Release v4.14.2 2026-03-18 09:18:33 +01:00
b5a22508ff Merge branch 'fix/fix-link-notification-email' into 'master'
Fix notification email links to handle user and non-user contexts

See merge request Chill-Projet/chill-bundles!973
2026-03-18 08:16:41 +00:00
f12bc2f35f Fix notification email links to handle user and non-user contexts 2026-03-18 08:16:40 +00:00
9ba8ec8f41 Release v4.14.1 2026-03-16 15:55:52 +01:00
6a66f05451 Merge branch '506-fix-permissions-list-activity-by-person' into 'master'
Replace `ActivityVoter::SEE` with `AccompanyingPeriodVoter::SEE` for correct authorization check

Closes #506

See merge request Chill-Projet/chill-bundles!972
2026-03-16 14:54:47 +00:00
1524ed8ce9 Replace ActivityVoter::SEE with AccompanyingPeriodVoter::SEE for correct authorization check 2026-03-16 14:54:47 +00:00
0aa0824831 Merge branch '505-fix-user-group-notification-email' into 'master'
Resolve "Notification aux groupes utilisateurs"

Closes #505

See merge request Chill-Projet/chill-bundles!971
2026-03-16 14:08:36 +00:00
dd429ca02a Resolve "Notification aux groupes utilisateurs" 2026-03-16 14:08:35 +00:00
81193376a4 Merge branch '504-fix-random-tests' into 'master'
Add seeds to data fixtures, to avoid random failures in tests

Closes #504

See merge request Chill-Projet/chill-bundles!970
2026-03-09 13:00:30 +00:00
a921009eff Add seeds to data fixtures, to avoid random failures in tests 2026-03-09 13:00:30 +00:00
e2dec28577 Release v4.14.0
- Implemented `ReferrerMainCenterAggregatorTest` to validate data transformation and query logic.
- Added data providers and query builders to ensure comprehensive test coverage.
- Verified correct handling of rolling dates and aggregator logic.
2026-03-09 12:27:00 +01:00
30385da409 Merge branch '486-user-center-filter-aggregator' into 'master'
Resolve "Create a filter/aggregator by user center for the exports"

Closes #486

See merge request Chill-Projet/chill-bundles!946
2026-03-09 11:19:38 +00:00
562fecb4aa Resolve "Create a filter/aggregator by user center for the exports" 2026-03-09 11:19:38 +00:00
8e8f459f90 Merge branch '503-reassign-ui-message' into 'master'
Resolve "Lors de la ré-assignation des parcours, l'UI ne mentionne pas qu'une opération a été réalisée"

Closes #503

See merge request Chill-Projet/chill-bundles!969
2026-03-09 09:25:08 +00:00
5de3862ec2 Resolve "Lors de la ré-assignation des parcours, l'UI ne mentionne pas qu'une opération a été réalisée" 2026-03-09 09:25:08 +00:00
26838648c8 Merge branch '502-fix-import-postal-code-removed' into 'master'
Resolve "Lors de l'import de code postaux, les codes absents de l'import depuis la même source ne sont pas supprimés"

Closes #502

See merge request Chill-Projet/chill-bundles!968
2026-02-23 20:05:05 +00:00
030553a4de Resolve "Lors de l'import de code postaux, les codes absents de l'import depuis la même source ne sont pas supprimés" 2026-02-23 20:05:04 +00:00
966f9f7e33 Release v4.13.0 2026-02-23 17:13:24 +01:00
7a5300b713 Merge branch '495-fix-quote-notification-email' into 'master'
Remove unused method `sendNotificationEmailsToAddressesEmails` from `NotificationMailer`

Closes #495

See merge request Chill-Projet/chill-bundles!967
2026-02-23 15:49:39 +00:00
dc3a585e5b Remove unused method sendNotificationEmailsToAddressesEmails from NotificationMailer 2026-02-23 15:49:39 +00:00
7712d76889 Merge branch '494-titre-toute-la-journée-tronqué-sur-la-page-mes-rendez-vous' into 'master'
Resolve "Titre 'Toute la journée' tronqué sur la page Mes Rendez-vous"

Closes #494

See merge request Chill-Projet/chill-bundles!965
2026-02-23 15:08:48 +00:00
Boris Waaub
69bb7026c9 Resolve "Titre 'Toute la journée' tronqué sur la page Mes Rendez-vous" 2026-02-23 15:08:48 +00:00
acd7240903 Merge branch '501-fix-deprecation-markdown-parser' into 'master'
Resolve "Depréciation dans le paquet de transformation markdown"

Closes #501

See merge request Chill-Projet/chill-bundles!966
2026-02-23 14:50:15 +00:00
22049558da Resolve "Depréciation dans le paquet de transformation markdown" 2026-02-23 14:50:14 +00:00
c0f2f3f3e0 Merge branch '500-limit-public-download' into 'master'
Resolve "Téléchargement des documents d'un workflow: limiter à 30 téléchargements plutôt que 100"

Closes #500

See merge request Chill-Projet/chill-bundles!964
2026-02-23 14:24:53 +00:00
bf56b3cc65 Resolve "Téléchargement des documents d'un workflow: limiter à 30 téléchargements plutôt que 100" 2026-02-23 14:24:53 +00:00
f85973f7ae Merge branch '499-fix-loading-postal-code' into 'master'
Resolve "Des codes postaux marqués comme supprimés apparaissent toujours dans la recherche d'adresse"

Closes #499

See merge request Chill-Projet/chill-bundles!963
2026-02-23 14:16:46 +00:00
f1446d7abe Resolve "Des codes postaux marqués comme supprimés apparaissent toujours dans la recherche d'adresse" 2026-02-23 14:16:45 +00:00
76d675ac02 Fixed translations of address in exports (addresse -> adresse) 2026-02-17 14:11:15 +01:00
cf0a2b7393 Merge branch '438-parcours-designer-comme-adresse-du-parcours-to-be-green' into 'master'
Resolve "Parcours - "Désigner comme adresse du parcours" to be green"

Closes #438

See merge request Chill-Projet/chill-bundles!958
2026-02-12 08:50:00 +00:00
Boris Waaub
80b05a8133 Resolve "Parcours - "Désigner comme adresse du parcours" to be green" 2026-02-12 08:50:00 +00:00
69aba8d9c9 Merge branch 'changie/add-mr-to-question' into 'master'
Changie/add mr to question

See merge request Chill-Projet/chill-bundles!960
2026-02-11 13:27:48 +00:00
a87d936828 Changie/add mr to question 2026-02-11 13:27:48 +00:00
290fa7a77c Merge branch '498-fix-workflow-initiator' into 'master'
Take workflow creator into account when granting edit permissions on documents

Closes #498

See merge request Chill-Projet/chill-bundles!959
2026-02-10 15:05:50 +00:00
0e1d233d79 Take workflow creator into account when granting edit permissions on documents 2026-02-10 15:05:49 +00:00
3402e4863f Release v4.12.1 2026-02-01 18:52:21 +01:00
1f0974ea68 Merge branch 'cs/update-cs-fixer-3.93' into 'master'
Update PHP-CS-Fixer to version 3.93.0 in composer dependencies

See merge request Chill-Projet/chill-bundles!955
2026-01-29 12:27:56 +00:00
9997fb287a Update PHP-CS-Fixer to version 3.93.0 in composer dependencies 2026-01-29 12:27:56 +00:00
f9a9de1148 Merge branch '496-allow-remove-double-refid-ban-address-importer' into 'master'
Adding the option to deal with duplicate addresses in the BAN importer

Closes #496

See merge request Chill-Projet/chill-bundles!954
2026-01-27 10:26:57 +00:00
juminet
c34f720f94 Adding the option to deal with duplicate addresses in the BAN importer 2026-01-27 10:26:57 +00:00
e1b1f592fa Merge branch 'zimbra/use-delegated-admin' into 'master'
[Zimbra] Use admin delegated account for authenticating users against Zimbra

See merge request Chill-Projet/chill-bundles!952
2026-01-22 14:39:46 +00:00
8546f4dadc [Zimbra] Use admin delegated account for authenticating users against Zimbra 2026-01-22 14:39:46 +00:00
4028c020ee Release v4.12.0 2026-01-15 18:02:12 +01:00
0d4eef6a0c Merge branch '493-fix-stored-object-workflow-permission' into 'master'
Fix issues with permission for stored objects associated with workflows

Closes #493

See merge request Chill-Projet/chill-bundles!951
2026-01-15 16:54:37 +00:00
b6152d5356 Fix issues with permission for stored objects associated with workflows 2026-01-15 16:54:37 +00:00
8b708f8c73 fix CommentInput: replace deprecated value binding with model-value 2026-01-15 14:53:40 +01:00
8d5b200107 Restrict ux-translator version to 2.31.0 2026-01-15 14:44:05 +01:00
a9e9207d5a Update php-cs-fixer version 2026-01-15 13:41:00 +01:00
3915574ed4 phpstan error fix 2026-01-15 13:40:46 +01:00
f3217d22ef Fix: acc periods of which user is the referrer should not be included if when the list is filtered by center and none of the participations are part of the center 2026-01-15 13:25:54 +01:00
06c5affbe7 Increase delay for removing stale workflows from 90 to 180 days
- Updated `KEEP_INTERVAL` in `CancelStaleWorkflowCronJob` to `P180D`.
2026-01-15 10:08:40 +01:00
bf461a1211 Merge branch '473-display-bundles-version' into 'master'
Resolve "Afficher le numéro de version de Chill dans l'UX"

Closes #473

See merge request Chill-Projet/chill-bundles!947
2026-01-13 15:35:26 +00:00
3f0ad51114 Resolve "Afficher le numéro de version de Chill dans l'UX" 2026-01-13 15:35:26 +00:00
a4de8eaab3 Merge branch '489-fix-desactivation-date-goarls-results' into 'master'
Fix issue with goal/result deactivation date handling and improve formatting

Closes #489

See merge request Chill-Projet/chill-bundles!949
2026-01-13 15:32:08 +00:00
2feb137ac2 Fix issue with goal/result deactivation date handling and improve formatting 2026-01-13 15:32:07 +00:00
5ea74d118b Merge branch '490-fix-double-notification' into 'master'
Prevent notifications from being sent when the user signs a document he asked to himself

Closes #490

See merge request Chill-Projet/chill-bundles!950
2026-01-13 15:31:50 +00:00
8eb7a55ef5 Prevent notifications from being sent when the user signs a document he asked to himself 2026-01-13 15:31:49 +00:00
281887355f Fix calculation of budget balance 2026-01-12 10:34:30 +01:00
47b285b584 Fix export group by center for persons without a center in CenterAggregator.php 2025-12-30 13:01:56 +01:00
7c9b4d02f6 Fix ordering of social actions
Actions with a closing date in the future should be considered as 'still open'.
2025-12-18 11:08:18 +01:00
3ff9bba4de Fix the condition to display concerned persons in calendar list items. 2025-12-18 10:24:24 +01:00
c0f9e953fb Update to v4.11.0 2025-12-17 16:56:35 +01:00
a49ea2b6b9 Fix translation syntax
Cannot start with %, wrap translation value in double quotes
2025-12-17 16:54:33 +01:00
313 changed files with 4009 additions and 1683 deletions

View File

@@ -0,0 +1,8 @@
kind: DX
body: 'Changie: add a field for adding a release note tag when creating an entry in changie.'
time: 2026-03-24T15:38:05.320350835+01:00
custom:
IRN: "No"
Issue: ""
MR: ""
SchemaChange: No schema change

View File

@@ -1,6 +0,0 @@
kind: Feature
body: 'Add filtering to admin lists: social actions, social issues, goals, results, and evaluations'
time: 2025-12-10T03:20:45.135973502+01:00
custom:
Issue: "478"
SchemaChange: No schema change

View File

@@ -0,0 +1,7 @@
kind: Feature
body: Add a field "externalId" on center, to ease the synchronisation of centers with external tools
time: 2026-03-24T16:40:18.159561269+01:00
custom:
Issue: "507"
MR: "977"
SchemaChange: Add columns or tables

View File

@@ -1,7 +0,0 @@
kind: Fixed
body: |
Fix migration query after previous fix
time: 2025-12-11T21:49:08.899926492+01:00
custom:
Issue: "466"
SchemaChange: No schema change

9
.changes/v4.11.0.md Normal file
View File

@@ -0,0 +1,9 @@
## v4.11.0 - 2025-12-17
### Feature
* ([#478](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/478)) Add filtering to admin lists: social actions, social issues, goals, results, and evaluations
### Fixed
* ([#466](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/466)) Fix migration query after previous fix
* Fix translation key/value
Cannot start with % and should be wrapped in "".

16
.changes/v4.12.0.md Normal file
View File

@@ -0,0 +1,16 @@
## v4.12.0 - 2026-01-15
### Feature
* ([#473](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/473)) Display version of chill bundles in application footer
* Increase the delay before removing stale workflow from 90 days to 180 days.
### Fixed
* ([#480](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/480)) Fix the condition to display concerned persons in calendar list items.
* ([#481](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/481)) Fix ordering of social actions: actions with a closing date in the future should be considered as 'still open'.
* ([#477](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/477)) Fix export group by center for persons without a center in CenterAggregator.php
* Fix the calculation of budget balance to only take into account resources and charges that are still actual
* ([#489](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/489)) Fix desactivation date for Goals and results
* ([#490](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/490)) Prevent sending a notification when the user signs the document himself
* ([#491](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/491)) Fix: acc periods of which user is the referrer should not be included if when the list is filtered by center and none of the participations are part of the center
* ([#492](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/492)) fix CommentInput: replace deprecated value binding with model-value
* ([#493](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/493)) fix issue with stored object permissions associated with workflows (as attachment, or through a related entity)
BC: the constructor's signature of `\Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter` has changed.

4
.changes/v4.12.1.md Normal file
View File

@@ -0,0 +1,4 @@
## v4.12.1 - 2026-02-01
### Fixed
* ([#496](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/496)) Add the option to deal with duplicate address in BAN adress importer

15
.changes/v4.13.0.md Normal file
View File

@@ -0,0 +1,15 @@
## v4.13.0 - 2026-02-23
### Feature
* ([#500](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/500)) ([!964](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/964)) Limit the number of public download of stored object to 30 downloads
* ([#495](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/495)) ([!967](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/967)) Send email related to notification in both html and txt format, and render quote correctly
### Fixed
* ([#438](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/438)) Change wrong color of submit button "Désigner comme adresse du parcours"
* ([#498](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/498)) For giving edit permissions on documents, take into account the workflow creator
* Fixed mispelling of address in translations: addresse -> adresse
* ([#499](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/499)) ([!963](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/963)) Fix: some postal code appears in the UI, although they are marked as deleted
* ([#501](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/501)) ([!966](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/966)) Fix deprecation in the markdown rendering
* ([#494](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/494)) ([!965](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/965)) Remove unused all-day slot display
### DX
* ([!960](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/960)) Configure changie to ask for merge request number for a better tracking of changes

6
.changes/v4.14.0.md Normal file
View File

@@ -0,0 +1,6 @@
## v4.14.0 - 2026-03-09
### Feature
* ([#486](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/486)) ([!<no value>](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/<no value>)) Add filter and aggregator based on referrer's main center for exports of accompanying period
### Fixed
* ([#502](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/502)) ([!968](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/968)) Fix import of postal code: mark postal code as deleted if they are not present in the import any more
* ([#503](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/503)) ([!969](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/969)) Add a flash message when reassigning accompanying course (reassign list)

5
.changes/v4.14.1.md Normal file
View File

@@ -0,0 +1,5 @@
## v4.14.1 - 2026-03-16
### Security
* ([#506](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/506)) ([!972](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/972)) Fix permission in list of activities in person context
### DX
* ([#504](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/504)) ([!970](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/970)) Add seeds in DataFixtures and in some tests to avoid random test failures

3
.changes/v4.14.2.md Normal file
View File

@@ -0,0 +1,3 @@
## v4.14.2 - 2026-03-18
### Fixed
* Fix link inside notification email

View File

@@ -7,7 +7,7 @@ versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}'
kindFormat: '### {{.Kind}}'
# Note: it is possible to add a `.custom.Long` text manually into the yaml file produced by `changie new`. This will add a long description.
changeFormat: >-
* {{ if not (eq .Custom.Issue "") }}([#{{ .Custom.Issue }}](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/{{ .Custom.Issue }})) {{ end }}{{ .Body }} {{ if and .Custom.SchemaChange (ne .Custom.SchemaChange "No schema change") }}
* {{ if not (eq .Custom.Issue "") }}([#{{ .Custom.Issue }}](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/{{ .Custom.Issue }})) {{ end }}{{ if not (eq .Custom.MR "") }}([!{{ .Custom.MR }}](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/{{ .Custom.MR }})) {{ end }}{{ .Body }} {{ if (eq .Custom.IRN "Yes") }}(RN){{ end }} {{ if and .Custom.SchemaChange (ne .Custom.SchemaChange "No schema change") }}
**Schema Change**: {{ .Custom.SchemaChange }}
{{- end -}}
@@ -30,6 +30,20 @@ custom:
type: int
minInt: 1
- key: MR
label: Merge request number (on chill-bundles repository) (optional)
optional: true
type: int
minInt: 1
- key: IRN
label: Is this interesting for release notes ?
optional: false
type: enum
enumOptions:
- "No"
- "Yes"
body:
# allow multiline messages
block: true

13
.gitignore vendored
View File

@@ -50,12 +50,15 @@ phpstan.neon
###> symfony/phpunit-bridge ###
###< symfony/phpunit-bridge ###
###> symfony/webpack-encore-bundle ###
/node_modules/
/public/build/
npm-debug.log
yarn-error.log
###< symfony/webpack-encore-bundle ###
###> friendsofphp/php-cs-fixer ###
/.php-cs-fixer.php
/.php-cs-fixer.cache
###< friendsofphp/php-cs-fixer ###
###> pentatrion/vite-bundle ###
/node_modules/
/public/build/
###< pentatrion/vite-bundle ###

View File

@@ -238,13 +238,13 @@ The tests are run from the project's root (not from the bundle's root).
```bash
# Run all tests
vendor/bin/phpunit
symfony composer exec phpunit
# Run a specific test file
vendor/bin/phpunit path/to/TestFile.php
symfony composer exec phpunit -- path/to/TestFile.php
# Run a specific test method
vendor/bin/phpunit --filter methodName path/to/TestFile.php
symfony composer exec phpunit --filter methodName path/to/TestFile.php
```
When writing tests, only test specific files. Do not run all tests or the full

View File

@@ -6,6 +6,71 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v4.14.2 - 2026-03-18
### Fixed
* Fix link inside notification email
## v4.14.1 - 2026-03-16
### Security
* ([#506](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/506)) ([!972](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/972)) Fix permission in list of activities in person context
### DX
* ([#504](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/504)) ([!970](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/970)) Add seeds in DataFixtures and in some tests to avoid random test failures
## v4.14.0 - 2026-03-09
### Feature
* ([#486](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/486)) ([!<no value>](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/<no value>)) Add filter and aggregator based on referrer's main center for exports of accompanying period
### Fixed
* ([#502](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/502)) ([!968](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/968)) Fix import of postal code: mark postal code as deleted if they are not present in the import any more
* ([#503](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/503)) ([!969](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/969)) Add a flash message when reassigning accompanying course (reassign list)
## v4.13.0 - 2026-02-23
### Feature
* ([#500](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/500)) ([!964](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/964)) Limit the number of public download of stored object to 30 downloads
* ([#495](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/495)) ([!967](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/967)) Send email related to notification in both html and txt format, and render quote correctly
### Fixed
* ([#438](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/438)) Change wrong color of submit button "Désigner comme adresse du parcours"
* ([#498](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/498)) For giving edit permissions on documents, take into account the workflow creator
* Fixed mispelling of address in translations: addresse -> adresse
* ([#499](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/499)) ([!963](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/963)) Fix: some postal code appears in the UI, although they are marked as deleted
* ([#501](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/501)) ([!966](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/966)) Fix deprecation in the markdown rendering
* ([#494](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/494)) ([!965](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/965)) Remove unused all-day slot display
### DX
* ([!960](https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/960)) Configure changie to ask for merge request number for a better tracking of changes
## v4.12.1 - 2026-02-01
### Fixed
* ([#496](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/496)) Add the option to deal with duplicate address in BAN adress importer
## v4.12.0 - 2026-01-15
### Feature
* ([#473](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/473)) Display version of chill bundles in application footer
* Increase the delay before removing stale workflow from 90 days to 180 days.
### Fixed
* ([#480](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/480)) Fix the condition to display concerned persons in calendar list items.
* ([#481](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/481)) Fix ordering of social actions: actions with a closing date in the future should be considered as 'still open'.
* ([#477](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/477)) Fix export group by center for persons without a center in CenterAggregator.php
* Fix the calculation of budget balance to only take into account resources and charges that are still actual
* ([#489](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/489)) Fix desactivation date for Goals and results
* ([#490](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/490)) Prevent sending a notification when the user signs the document himself
* ([#491](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/491)) Fix: acc periods of which user is the referrer should not be included if when the list is filtered by center and none of the participations are part of the center
* ([#492](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/492)) fix CommentInput: replace deprecated value binding with model-value
* ([#493](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/493)) fix issue with stored object permissions associated with workflows (as attachment, or through a related entity)
BC: the constructor's signature of `\Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter` has changed.
## v4.11.0 - 2025-12-17
### Feature
* ([#478](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/478)) Add filtering to admin lists: social actions, social issues, goals, results, and evaluations
### Fixed
* ([#466](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/466)) Fix migration query after previous fix
* Fix translation key/value
Cannot start with % and should be wrapped in "".
## v4.10.1 - 2025-12-11
### Fixed
* Fix missing translation variable in NewLocation component

View File

@@ -21,6 +21,7 @@
"ext-openssl": "*",
"ext-redis": "*",
"ext-zlib": "*",
"composer-runtime-api": "*",
"champs-libres/wopi-bundle": "dev-symfony-v5@dev",
"champs-libres/wopi-lib": "dev-master@dev",
"doctrine/data-fixtures": "^1.8",
@@ -37,7 +38,6 @@
"ocramius/package-versions": "^1.10 || ^2",
"odolbeau/phone-number-bundle": "^3.6",
"ovh/ovh": "^3.0",
"pentatrion/vite-bundle": "^8.2",
"phpoffice/phpspreadsheet": "^1.16",
"ramsey/uuid-doctrine": "^1.7",
"sensio/framework-extra-bundle": "^5.5",
@@ -83,8 +83,9 @@
"symfony/templating": "^5.4",
"symfony/translation": "^5.4",
"symfony/twig-bundle": "^5.4",
"symfony/ux-translator": "^2.22",
"symfony/ux-translator": "2.31.0",
"symfony/validator": "^5.4",
"symfony/webpack-encore-bundle": "^1.11",
"symfony/workflow": "^5.4",
"symfony/yaml": "^5.4",
"thenetworg/oauth2-azure": "^2.0",
@@ -97,7 +98,7 @@
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3",
"fakerphp/faker": "^1.13",
"friendsofphp/php-cs-fixer": "3.65.0",
"friendsofphp/php-cs-fixer": "3.93.0",
"jangregor/phpstan-prophecy": "^1.0",
"nelmio/alice": "^3.8",
"nikic/php-parser": "^4.15",

View File

@@ -17,6 +17,7 @@ return [
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Chill\ActivityBundle\ChillActivityBundle::class => ['all' => true],
@@ -36,5 +37,4 @@ return [
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
loophp\PsrHttpMessageBridgeBundle\PsrHttpMessageBridgeBundle::class => ['all' => true],
Pentatrion\ViteBundle\PentatrionViteBundle::class => ['all' => true],
];

View File

@@ -1,8 +1,6 @@
framework:
assets:
# Disable Encore-style manifest for default assets package. Vite (Pentatrion) uses public/build/.vite/manifest.json
# internally for vite_entry_* helpers; Symfony's asset() should not depend on a manifest.
json_manifest_path: null
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
when@test:
framework:

View File

@@ -8,5 +8,6 @@ when@dev: &dev
- 'file'
- 'md5'
- 'sha1'
seed: 1234567890
when@test: *dev

View File

@@ -0,0 +1,41 @@
webpack_encore:
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
output_path: '%kernel.project_dir%/public/build'
# If multiple builds are defined (as shown below), you can disable the default build:
# output_path: false
# Set attributes that will be rendered on all script and link tags
script_attributes:
defer: true
# Uncomment (also under link_attributes) if using Turbo Drive
# https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change
# 'data-turbo-track': reload
# link_attributes:
# Uncomment if using Turbo Drive
# 'data-turbo-track': reload
# If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
# crossorigin: 'anonymous'
# Preload all rendered script and link tags automatically via the HTTP/2 Link header
# preload: true
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
# strict_mode: false
# If you have multiple builds:
# builds:
# frontend: '%kernel.project_dir%/public/frontend/build'
# pass the build name as the 3rd argument to the Twig functions
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
#when@prod:
# webpack_encore:
# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
# # Available in version 1.2
# cache: true
when@test:
webpack_encore:
strict_mode: false

View File

@@ -1,9 +0,0 @@
when@dev:
_pentatrion_vite:
prefix: /build
resource: "@PentatrionViteBundle/Resources/config/routing.yaml"
_profiler_vite:
path: /_profiler/vite
defaults:
_controller: Pentatrion\ViteBundle\Controller\ProfilerController::info

View File

@@ -1,15 +1,6 @@
{
"name": "chill-bundles",
"private": true,
"name": "chill",
"version": "2.0.0",
"description": "Chill web application frontend (Vite build at repo root)",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"eslint": "eslint . --ext .js,.ts,.vue"
},
"devDependencies": {
"@alexlafroscia/yaml-merge": "^4.0.0",
"@apidevtools/swagger-cli": "^4.0.4",
@@ -20,11 +11,11 @@
"@hotwired/stimulus": "^3.0.0",
"@luminateone/eslint-baseline": "^1.0.9",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/webpack-encore": "^4.1.0",
"@tsconfig/node20": "^20.1.4",
"@types/dompurify": "^3.0.5",
"@types/eslint__js": "^8.42.3",
"@typescript-eslint/parser": "^8.12.2",
"@vitejs/plugin-vue": "^5.1.4",
"bindings": "^1.5.0",
"bootstrap": "^5.3.6",
"chokidar": "^3.5.1",
@@ -49,9 +40,9 @@
"ts-loader": "^9.3.1",
"typescript": "^5.6.3",
"typescript-eslint": "^8.13.0",
"vite": "^5.4.8",
"vite-plugin-symfony": "^8",
"vue-loader": "^17.0.0"
"vue-loader": "^17.0.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
},
"dependencies": {
"@fullcalendar/core": "^6.1.4",
@@ -80,5 +71,21 @@
"vue-multiselect": "3.0.0-alpha.2",
"vue-toast-notification": "^3.1.2",
"vuex": "^4.0.0"
}
},
"browserslist": [
"defaults and fully supports es6-module and not dead"
],
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress",
"specs-build": "yaml-merge src/Bundle/ChillMainBundle/chill.api.specs.yaml src/Bundle/ChillPersonBundle/chill.api.specs.yaml src/Bundle/ChillCalendarBundle/chill.api.specs.yaml src/Bundle/ChillThirdPartyBundle/chill.api.specs.yaml src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml> templates/api/specs.yaml",
"specs-validate": "swagger-cli validate templates/api/specs.yaml",
"specs-create-dir": "mkdir -p templates/api",
"specs": "yarn run specs-create-dir && yarn run specs-build && yarn run specs-validate",
"version": "node --version",
"eslint": "npx eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
},
"private": true
}

View File

@@ -0,0 +1,3 @@
kind: Added
body: Use admin delegated account for handling authentication
time: 2026-01-22T15:32:23.932994899+01:00

View File

@@ -80,12 +80,19 @@ final readonly class CreateZimbraComponent
$location = $calendar->getCalendar()->getLocation();
$hasLocation = $calendar->getCalendar()->hasLocation();
$isPrivate = $calendar->getCalendar()->getAccompanyingPeriod()?->isConfidential() ?? false;
} else {
} elseif ($calendar instanceof Calendar) {
$startDate = $calendar->getStartDate();
$endDate = $calendar->getEndDate();
$location = $calendar->getLocation();
$hasLocation = $calendar->hasLocation();
$isPrivate = $calendar->getAccompanyingPeriod()?->isConfidential() ?? false;
} else {
// Calendar range case
$startDate = $calendar->getStartDate();
$endDate = $calendar->getEndDate();
$location = $calendar->getLocation();
$hasLocation = $calendar->hasLocation();
$isPrivate = false;
}
$comp = new InviteComponent();

View File

@@ -11,48 +11,84 @@ declare(strict_types=1);
namespace Chill\ZimbraBundle\Calendar\Connector\ZimbraConnector;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpClient\Psr18Client;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Zimbra\Admin\AdminApi;
use Zimbra\Common\Enum\AccountBy;
use Zimbra\Common\Soap\ClientFactory;
use Zimbra\Common\Struct\AccountSelector;
use Zimbra\Common\Struct\Header\AccountInfo;
use Zimbra\Mail\MailApi;
final readonly class SoapClientBuilder
final class SoapClientBuilder
{
private string $username;
private readonly string $username;
private string $password;
private readonly string $password;
private string $url;
private readonly string $url;
public function __construct(private ParameterBagInterface $parameterBag, private HttpClientInterface $client)
{
private readonly string $adminUrl;
private readonly bool $verifyHost;
private readonly bool $verifyPeer;
private readonly bool $adminVerifyHost;
private readonly bool $adminVerifyPeer;
/**
* Keep the cache of the tokens.
*
* @var array<string, array{token: string, expirationTime: \DateTimeImmutable}>
*/
private array $tokenCache = [];
public function __construct(
private readonly ParameterBagInterface $parameterBag,
private readonly HttpClientInterface $client,
private readonly ClockInterface $clock,
) {
$dsn = $this->parameterBag->get('chill_calendar.remote_calendar_dsn');
$url = parse_url($dsn);
$this->username = urldecode($url['user']);
$this->password = urldecode($url['pass']);
if ('zimbra+http' === $url['scheme']) {
$scheme = 'http://';
$scheme = 'http';
$port = $url['port'] ?? 80;
} elseif ('zimbra+https' === $url['scheme']) {
$scheme = 'https://';
$scheme = 'https';
$port = $url['port'] ?? 443;
} else {
throw new \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException('Unsupported remote calendar scheme: '.$url['scheme']);
}
$this->url = $scheme.$url['host'].':'.$port;
// get attributes for adminUrl
$query = [];
parse_str($url['query'] ?? '', $query);
$adminPort = $query['adminPort'] ?? '7071';
$adminHost = $query['adminHost'] ?? $url['host'];
$adminScheme = $query['adminScheme'] ?? $scheme;
$this->verifyPeer = (bool) ($query['verifyPeer'] ?? true);
$this->verifyHost = (bool) ($query['verifyHost'] ?? true);
$this->adminVerifyHost = (bool) ($query['adminVerifyHost'] ?? $this->verifyPeer);
$this->adminVerifyPeer = (bool) ($query['adminVerifyPeer'] ?? $this->verifyHost);
$this->url = $scheme.'://'.$url['host'].':'.$port;
$this->adminUrl = $adminScheme.'://'.$adminHost.':'.$adminPort;
}
private function buildApi(): MailApi
{
$baseClient = $this->client->withOptions([
'base_uri' => $location = $this->url.'/service/soap',
'verify_host' => false,
'verify_peer' => false,
'verify_host' => $this->verifyHost,
'verify_peer' => $this->verifyPeer,
]);
$psr18Client = new Psr18Client($baseClient);
$api = new MailApi();
@@ -62,12 +98,36 @@ final readonly class SoapClientBuilder
return $api;
}
private function buildAdminApi(): AdminApi
{
$baseClient = $this->client->withOptions([
'base_uri' => $location = $this->adminUrl.'/service/admin/soap',
'verify_host' => $this->adminVerifyHost,
'verify_peer' => $this->adminVerifyPeer,
]);
$psr18Client = new Psr18Client($baseClient);
$api = new AdminApi();
$client = ClientFactory::create($location, $psr18Client);
$api->setClient($client);
return $api;
}
public function getApiForAccount(string $accountName): MailApi
{
$api = $this->buildApi();
$response = $api->authByAccountName($this->username, $this->password);
['token' => $token, 'expirationTime' => $expirationTime] = $this->tokenCache[$accountName]
?? ['token' => null, 'expirationTime' => null];
$token = $response->getAuthToken();
if (null === $token || null === $expirationTime || $expirationTime <= $this->clock->now()) {
$adminApi = $this->buildAdminApi();
$adminApi->auth($this->username, $this->password);
$delegateResponse = $adminApi->delegateAuth(new AccountSelector(AccountBy::NAME, $accountName));
$token = $delegateResponse->getAuthToken();
$expiration = $delegateResponse->getLifetime();
$expirationTime = $this->clock->now()->add(new \DateInterval('PT'.$expiration.'S'));
$this->tokenCache[$accountName] = ['token' => $token, 'expirationTime' => $expirationTime];
}
$apiBy = $this->buildApi();
$apiBy->setAuthToken($token);

View File

@@ -33,6 +33,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
public function __construct(private readonly EntityManagerInterface $em)
{
mt_srand(123456789);
$this->faker = FakerFactory::create('fr_FR');
}
@@ -48,7 +49,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
->findAll();
foreach ($persons as $person) {
$activityNbr = random_int(0, 3);
$activityNbr = mt_rand(0, 3);
for ($i = 0; $i < $activityNbr; ++$i) {
$activity = $this->newRandomActivity($person);
@@ -73,7 +74,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
// ->setAttendee($this->faker->boolean())
for ($i = 0; random_int(0, 4) > $i; ++$i) {
for ($i = 0; mt_rand(0, 4) > $i; ++$i) {
$reason = $this->getRandomActivityReason();
if (null !== $reason) {

View File

@@ -69,7 +69,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
}
/** (non-PHPdoc).
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
* @see PrependExtensionInterface::prepend()
*/
public function prependRoutes(ContainerBuilder $container)
{

View File

@@ -24,6 +24,7 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInt
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
@@ -340,7 +341,7 @@ final readonly class ActivityACLAwareRepository implements ActivityACLAwareRepos
}
foreach ($person->getAccompanyingPeriodParticipations() as $participation) {
if (!$this->security->isGranted(ActivityVoter::SEE, $participation->getAccompanyingPeriod())) {
if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $participation->getAccompanyingPeriod())) {
continue;
}

View File

@@ -1 +1 @@
import "./chillactivity.scss";
require("./chillactivity.scss");

View File

@@ -124,9 +124,9 @@
{# {{ form(delete_form) }} #}
{% block js %}
{{ vite_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_pickentity_type') }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}

View File

@@ -15,7 +15,7 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
@@ -23,12 +23,12 @@
});
window.activity = {{ activity_json|json_encode|raw }};
</script>
{{ vite_entry_script_tags('vue_activity') }}
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ vite_entry_link_tags('vue_activity') }}
{{ vite_entry_link_tags('page_edit_activity') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{{ encore_entry_link_tags('page_edit_activity') }}
{% endblock %}

View File

@@ -30,7 +30,7 @@
{% endblock %}
{% block js %}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
@@ -38,10 +38,10 @@
});
window.activity = {{ activity_json|json_encode|raw }};
</script>
{{ vite_entry_script_tags('vue_activity') }}
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ vite_entry_link_tags('vue_activity') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -7,14 +7,14 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}

View File

@@ -22,14 +22,14 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}

View File

@@ -121,9 +121,9 @@
{{ form_end(form) }}
{% block js %}
{{ vite_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}

View File

@@ -15,16 +15,16 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
<script type="text/javascript">
window.activity = {{ activity_json|json_encode|raw }};
{% if default_location is not null %}window.default_location_id = {{ default_location.id }}{% endif %};
</script>
{{ vite_entry_script_tags('vue_activity') }}
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ vite_entry_link_tags('vue_activity') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -14,7 +14,7 @@
{% endblock %}
{% block js %}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ 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 }}"]',
@@ -22,10 +22,10 @@
});
window.activity = {{ activity_json|json_encode|raw }};
</script>
{{ vite_entry_script_tags('vue_activity') }}
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ vite_entry_link_tags('vue_activity') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -6,16 +6,16 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% import '@ChillActivity/ActivityReason/macro.html.twig' as m %}

View File

@@ -6,14 +6,14 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% import '@ChillActivity/ActivityReason/macro.html.twig' as m %}

View File

@@ -16,7 +16,8 @@ use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelperInterface;
use Symfony\Component\Security\Core\Security;
class ActivityStoredObjectVoter extends AbstractStoredObjectVoter
@@ -24,9 +25,10 @@ class ActivityStoredObjectVoter extends AbstractStoredObjectVoter
public function __construct(
private readonly ActivityRepository $repository,
Security $security,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
WorkflowRelatedEntityPermissionHelperInterface $workflowDocumentService,
EntityWorkflowAttachmentRepository $attachmentRepository,
) {
parent::__construct($security, $workflowDocumentService);
parent::__construct($security, $attachmentRepository, $workflowDocumentService);
}
protected function getRepository(): AssociatedEntityToStoredObjectInterface

View File

@@ -0,0 +1,18 @@
// this file loads all assets from the Chill person bundle
module.exports = function (encore, entries) {
entries.push(__dirname + "/Resources/public/chill/index.js");
encore.addAliases({
ChillActivityAssets: __dirname + "/Resources/public",
});
encore.addEntry(
"page_edit_activity",
__dirname + "/Resources/public/page/edit_activity/index.scss",
);
encore.addEntry(
"vue_activity",
__dirname + "/Resources/public/vuejs/Activity/index.js",
);
};

View File

@@ -1,14 +0,0 @@
export default {
chillBase: [
"./src/Bundle/ChillActivityBundle/Resources/public/chill/index.js",
],
aliases: {
ChillActivityAssets: "./src/Bundle/ChillActivityBundle/Resources/public",
},
inputs: {
page_edit_activity:
"./src/Bundle/ChillActivityBundle/Resources/public/page/edit_activity/index.scss",
vue_activity:
"./src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/index.js",
},
};

View File

@@ -21,7 +21,10 @@ use Doctrine\Persistence\ObjectManager;
class LoadAsideActivity extends Fixture implements DependentFixtureInterface
{
public function __construct(private readonly UserRepository $userRepository) {}
public function __construct(private readonly UserRepository $userRepository)
{
mt_srand(123456789);
}
public function getDependencies(): array
{
@@ -47,7 +50,7 @@ class LoadAsideActivity extends Fixture implements DependentFixtureInterface
$this->getReference('aside_activity_category_0', AsideActivityCategory::class)
)
->setDate((new \DateTimeImmutable('today'))
->sub(new \DateInterval('P'.\random_int(1, 100).'D')));
->sub(new \DateInterval('P'.\mt_rand(1, 100).'D')));
$manager->persist($activity);
}

View File

@@ -2,12 +2,12 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_pickentity_type') }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block title %}

View File

@@ -56,7 +56,7 @@ class ChillBudgetExtension extends Extension implements PrependExtensionInterfac
}
/** (non-PHPdoc).
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
* @see PrependExtensionInterface::prepend()
*/
public function prependRoutes(ContainerBuilder $container)
{

View File

@@ -1 +1 @@
import("./chillbudget.scss");
require("./chillbudget.scss");

View File

@@ -72,14 +72,20 @@
{% macro table_results(actualCharges, actualResources, results) %}
{% set now = date() %}
{% set totalCharges = 0 %}
{% for c in actualCharges %}
{% set totalCharges = totalCharges + c.amount %}
{% if c.startDate <= now and (c.endDate is null or c.endDate >= now) %}
{% set totalCharges = totalCharges + c.amount %}
{% endif %}
{% endfor %}
{% set totalResources = 0 %}
{% for r in actualResources %}
{% set totalResources = totalResources + r.amount %}
{% if r.startDate <= now and (r.endDate is null or r.endDate >= now) %}
{% set totalResources = totalResources + r.amount %}
{% endif %}
{% endfor %}
{% set result = (totalResources - totalCharges) %}

View File

@@ -7,11 +7,11 @@
{% block title title %}
{% block js %}
{{ vite_entry_script_tags('page_budget') }}
{{ encore_entry_script_tags('page_budget') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('page_budget') }}
{{ encore_entry_link_tags('page_budget') }}
{% endblock %}
{% block content %}

View File

@@ -7,11 +7,11 @@
{% block title title %}
{% block js %}
{{ vite_entry_script_tags('page_budget') }}
{{ encore_entry_script_tags('page_budget') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('page_budget') }}
{{ encore_entry_link_tags('page_budget') }}
{% endblock %}
{% block content %}

View File

@@ -0,0 +1,8 @@
// this file loads all assets from the Chill budget bundle
module.exports = function (encore, entries) {
encore.addAliases({
ChillBudgetAssets: __dirname + "/Resources/public",
});
encore.addEntry("page_budget", __dirname + "/Resources/public/page/index.js");
};

View File

@@ -1,8 +0,0 @@
export default {
aliases: {
ChillBudgetAssets: "./src/Bundle/ChillBudgetBundle/Resources/public",
},
inputs: {
page_budget: "./src/Bundle/ChillBudgetBundle/Resources/public/page/index.js",
},
};

View File

@@ -1 +1 @@
import("./scss/calendar.scss");
require("./scss/calendar.scss");

View File

@@ -346,6 +346,7 @@ const baseOptions = ref<CalendarOptions>({
center: "title",
right: "timeGridWeek,timeGridDay",
},
allDaySlot: false,
});
const ranges = computed<EventInput[]>(() => {

View File

@@ -255,3 +255,5 @@ export default {
},
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>

View File

@@ -75,7 +75,7 @@
</div>
{% if calendar.comment.comment is not empty
or calendar.users|length > 0
or calendar.persons|length > 0
or calendar.thirdParties|length > 0
or calendar.users|length > 0 %}
<div class="item-row details separator">

View File

@@ -20,13 +20,13 @@
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
window.mainUser = {{ entity.mainUser.id }};
</script>
{{ vite_entry_script_tags('vue_calendar') }}
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('vue_calendar') }}
{{ vite_entry_link_tags('page_calendar') }}
{{ encore_entry_link_tags('vue_calendar') }}
{{ encore_entry_link_tags('page_calendar') }}
{% endblock %}
{% block block_post_menu %}

View File

@@ -20,13 +20,13 @@
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
window.mainUser = {{ entity.mainUser.id }};
</script>
{{ vite_entry_script_tags('vue_calendar') }}
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('vue_calendar') }}
{{ vite_entry_link_tags('page_calendar') }}
{{ encore_entry_link_tags('vue_calendar') }}
{{ encore_entry_link_tags('page_calendar') }}
{% endblock %}
{% block block_post_menu %}

View File

@@ -23,10 +23,10 @@
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
window.mainUser = {{ entity.mainUser.id }};
</script>
{{ vite_entry_script_tags('vue_calendar') }}
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('vue_calendar') }}
{{ encore_entry_link_tags('vue_calendar') }}
{% endblock %}

View File

@@ -9,14 +9,14 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_answer') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_answer') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_answer') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_answer') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}

View File

@@ -8,14 +8,14 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_answer') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_answer') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_answer') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_answer') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}

View File

@@ -16,10 +16,10 @@
<script type="text/javascript">
window.userId = {{ user.id }};
</script>
{{ vite_entry_script_tags('vue_mycalendarrange') }}
{{ encore_entry_script_tags('vue_mycalendarrange') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('vue_mycalendarrange') }}
{{ encore_entry_link_tags('vue_mycalendarrange') }}
{% endblock %}

View File

@@ -15,18 +15,18 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
<script type="text/javascript">
window.entity = {{ entity_json|json_encode|raw }};
{% if app.user.currentLocation is not null %}window.default_location_id = {{ app.user.currentLocation.id }};{% endif %};
</script>
{{ vite_entry_script_tags('vue_calendar') }}
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('vue_calendar') }}
{{ vite_entry_link_tags('mod_pickentity_type') }}
{{ encore_entry_link_tags('vue_calendar') }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block block_post_menu %}

View File

@@ -15,18 +15,18 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
<script type="text/javascript">
window.entity = {{ entity_json|json_encode|raw }};
{% if app.user.currentLocation is not null %}window.default_location_id = {{ app.user.currentLocation.id }};{% endif %};
</script>
{{ vite_entry_script_tags('vue_calendar') }}
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('vue_calendar') }}
{{ vite_entry_link_tags('mod_pickentity_type') }}
{{ encore_entry_link_tags('vue_calendar') }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block block_post_menu %}

View File

@@ -9,12 +9,12 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}
{% block content %}

View File

@@ -8,12 +8,12 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}
{% block content %}

View File

@@ -9,12 +9,12 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}
{% block content %}

View File

@@ -8,12 +8,12 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}
{% block content %}

View File

@@ -29,12 +29,12 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_answer') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_answer') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_answer') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_answer') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}

View File

@@ -0,0 +1,25 @@
// this file loads all assets from the Chill calendar bundle
module.exports = function (encore, entries) {
entries.push(__dirname + "/Resources/public/chill/chill.js");
encore.addAliases({
ChillCalendarAssets: __dirname + "/Resources/public",
});
encore.addEntry(
"vue_calendar",
__dirname + "/Resources/public/vuejs/Calendar/index.js",
);
encore.addEntry(
"vue_mycalendarrange",
__dirname + "/Resources/public/vuejs/MyCalendarRange/index2.ts",
);
encore.addEntry(
"page_calendar",
__dirname + "/Resources/public/chill/index.js",
);
encore.addEntry(
"mod_answer",
__dirname + "/Resources/public/module/Invite/answer.js",
);
};

View File

@@ -1,18 +0,0 @@
export default {
chillBase: [
"./src/Bundle/ChillCalendarBundle/Resources/public/chill/chill.js",
],
aliases: {
ChillCalendarAssets: "./src/Bundle/ChillCalendarBundle/Resources/public",
},
inputs: {
vue_calendar:
"./src/Bundle/ChillCalendarBundle/Resources/public/vuejs/Calendar/index.js",
vue_mycalendarrange:
"./src/Bundle/ChillCalendarBundle/Resources/public/vuejs/MyCalendarRange/index2.ts",
page_calendar:
"./src/Bundle/ChillCalendarBundle/Resources/public/chill/index.js",
mod_answer:
"./src/Bundle/ChillCalendarBundle/Resources/public/module/Invite/answer.js",
},
};

View File

@@ -41,6 +41,7 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface
public function __construct()
{
mt_srand(123456789);
$this->fakerFr = \Faker\Factory::create('fr_FR');
$this->fakerEn = \Faker\Factory::create('en_EN');
$this->fakerNl = \Faker\Factory::create('nl_NL');
@@ -104,7 +105,7 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface
$manager->persist($parent);
// Load children
$expected_nb_children = random_int(10, 50);
$expected_nb_children = mt_rand(10, 50);
for ($i = 0; $i < $expected_nb_children; ++$i) {
$companyName = $this->fakerFr->company;
@@ -144,7 +145,7 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface
$manager->persist($parent);
// Load children
$expected_nb_children = random_int(10, 50);
$expected_nb_children = mt_rand(10, 50);
for ($i = 0; $i < $expected_nb_children; ++$i) {
$manager->persist($this->createChildOption($parent, [

View File

@@ -52,7 +52,7 @@ class ChillCustomFieldsExtension extends Extension implements PrependExtensionIn
}
/** (non-PHPdoc).
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
* @see PrependExtensionInterface::prepend()
*/
public function prepend(ContainerBuilder $container)
{

View File

@@ -25,7 +25,7 @@ class ChoiceWithOtherType extends AbstractType
private string $otherValueLabel = 'Other value';
/** (non-PHPdoc).
* @see \Symfony\Component\Form\AbstractType::buildForm()
* @see AbstractType::buildForm()
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
@@ -42,7 +42,7 @@ class ChoiceWithOtherType extends AbstractType
}
/** (non-PHPdoc).
* @see \Symfony\Component\Form\AbstractType::configureOptions()
* @see AbstractType::configureOptions()
*/
public function configureOptions(OptionsResolver $resolver)
{

View File

@@ -22,7 +22,7 @@ use Symfony\Component\Form\FormEvents;
class ChoicesListType extends AbstractType
{
/** (non-PHPdoc).
* @see \Symfony\Component\Form\AbstractType::buildForm()
* @see AbstractType::buildForm()
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{

View File

@@ -82,7 +82,7 @@ class CustomFieldProvider implements ContainerAwareInterface
/**
* (non-PHPdoc).
*
* @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer()
* @see ContainerAwareInterface::setContainer()
*/
public function setContainer(?ContainerInterface $container = null)
{

View File

@@ -17,9 +17,9 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@@ -2,12 +2,12 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}

View File

@@ -17,9 +17,9 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@@ -3,11 +3,11 @@
{% block title 'docgen.Generate a document'|trans %}
{% block js %}
{{ vite_entry_script_tags('mod_pickentity_type') }}
{{ encore_entry_script_tags('mod_pickentity_type') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_pickentity_type') }}
{{ encore_entry_link_tags('mod_pickentity_type') }}
{% endblock %}
{% block content %}

View File

@@ -0,0 +1,11 @@
// this file loads all assets from the Chill DocGenerator bundle
module.exports = function (encore, entries) {
encore.addAliases({
ChillDocGeneratorAssets: __dirname + "/Resources/public",
});
encore.addEntry(
"mod_docgen_picktemplate",
__dirname + "/Resources/public/module/PickTemplate/index.js",
);
};

View File

@@ -1,10 +0,0 @@
export default {
aliases: {
ChillDocGeneratorAssets:
"./src/Bundle/ChillDocGeneratorBundle/Resources/public",
},
inputs: {
mod_docgen_picktemplate:
"./src/Bundle/ChillDocGeneratorBundle/Resources/public/module/PickTemplate/index.js",
},
};

View File

@@ -97,6 +97,12 @@ class StoredObject implements Document, TrackCreationInterface
#[ORM\OneToMany(mappedBy: 'storedObject', targetEntity: StoredObjectVersion::class, cascade: ['persist'], orphanRemoval: true)]
private Collection&Selectable $versions;
/**
* @var Collection<int, StoredObjectLock>
*/
#[ORM\OneToMany(mappedBy: 'storedObject', targetEntity: StoredObjectLock::class, cascade: ['persist', 'remove', 'refresh', 'merge'])]
private Collection $locks;
/**
* @param StoredObject::STATUS_* $status
*/
@@ -107,6 +113,41 @@ class StoredObject implements Document, TrackCreationInterface
$this->uuid = Uuid::uuid4();
$this->versions = new ArrayCollection();
$this->prefix = self::generatePrefix();
$this->locks = new ArrayCollection();
}
/**
* @internal use @see{StoredObjectLock::__construct}
*/
public function addLock(StoredObjectLock $lock): void
{
if (!$this->locks->contains($lock)) {
$this->locks->add($lock);
}
}
public function removeLock(StoredObjectLock $lock): void
{
$this->locks->removeElement($lock);
}
public function isLockedAt(\DateTimeImmutable $at): bool
{
foreach ($this->locks as $lock) {
if ($lock->isActiveAt($at)) {
return true;
}
}
return false;
}
/**
* @return Collection<int, StoredObjectLock>
*/
public function getLocks(): Collection
{
return $this->locks;
}
public function addGenerationTrial(): self

View File

@@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Entity;
use Chill\MainBundle\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
#[ORM\Entity]
#[ORM\Table(name: 'stored_object_lock', schema: 'chill_doc')]
class StoredObjectLock
{
#[ORM\Id]
#[ORM\Column(type: 'uuid', unique: true)]
private UuidInterface $uuid;
/**
* @var Collection<int, User>
*/
#[ORM\ManyToMany(targetEntity: User::class)]
#[ORM\JoinTable(name: 'stored_object_lock_user', schema: 'chill_doc')]
#[ORM\JoinColumn(referencedColumnName: 'uuid', nullable: false)]
private Collection $users;
/**
* @param list<User> $users
*/
public function __construct(
#[ORM\ManyToOne(targetEntity: StoredObject::class, inversedBy: 'locks')]
private StoredObject $storedObject,
#[ORM\Column(type: 'string', length: 10, nullable: false, enumType: StoredObjectLockMethodEnum::class)]
private StoredObjectLockMethodEnum $method,
#[ORM\Column(type: 'datetimetz_immutable', nullable: false)]
private \DateTimeImmutable $createdAt,
#[ORM\Column(type: 'text', nullable: false, options: ['default' => ''])]
private string $token = '',
#[ORM\Column(type: 'datetimetz_immutable', nullable: true)]
private ?\DateTimeImmutable $expireAt = null,
array $users = [],
) {
$this->uuid = Uuid::uuid7();
$this->users = new ArrayCollection();
$this->storedObject->addLock($this);
foreach ($users as $user) {
$this->addUser($user);
}
}
public function addUser(User $user): void
{
if (!$this->users->contains($user)) {
$this->users->add($user);
}
}
public function removeUser(User $user): void
{
$this->users->removeElement($user);
}
/**
* @return Collection<int, User>
*/
public function getUsers(): Collection
{
return $this->users;
}
public function setToken(string $token): void
{
$this->token = $token;
}
public function setExpireAt(?\DateTimeImmutable $expireAt): void
{
$this->expireAt = $expireAt;
}
public function getUuid(): UuidInterface
{
return $this->uuid;
}
public function getStoredObject(): StoredObject
{
return $this->storedObject;
}
public function getMethod(): StoredObjectLockMethodEnum
{
return $this->method;
}
public function getToken(): string
{
return $this->token;
}
public function getCreatedAt(): \DateTimeImmutable
{
return $this->createdAt;
}
public function getExpireAt(): ?\DateTimeImmutable
{
return $this->expireAt;
}
/**
* Return true if the lock must be considered as active.
*
* A StoredObjectLock is active if there isn't any expiration date, or
* if the expiration date and time is before the given time.
*/
public function isActiveAt(\DateTimeImmutable $at): bool
{
return null === $this->getExpireAt() || $at < $this->getExpireAt();
}
}

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Entity;
enum StoredObjectLockMethodEnum: string
{
case WEBDAV = 'webdav';
case WOPI = 'wopi';
}

View File

@@ -1,2 +1,2 @@
import("./uploader.js");
import("./downloader.js");
require("./uploader.js");
require("./downloader.js");

View File

@@ -22,8 +22,8 @@ import { initializeButtons } from "./downloader.js";
// load css
//require('dropzone/dist/basic.css');
import("dropzone/dist/dropzone.css");
import("./index.scss");
require("dropzone/dist/dropzone.css");
require("./index.scss");
//
// disable dropzone autodiscover

View File

@@ -366,7 +366,7 @@ import {
} from "../../types";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import * as pdfjsLib from "pdfjs-dist";
import type {
import {
PDFDocumentProxy,
PDFPageProxy,
} from "pdfjs-dist/types/src/display/api";

View File

@@ -42,10 +42,10 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@@ -38,10 +38,10 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@@ -12,9 +12,9 @@
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ vite_entry_link_tags('mod_entity_workflow_pick') }}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_entity_workflow_pick') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}
@@ -80,7 +80,7 @@
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ vite_entry_script_tags('mod_entity_workflow_pick') }}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_entity_workflow_pick') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}

View File

@@ -3,14 +3,14 @@ activeRouteKey = '' %} {% block title %}
{{ "Documents" }}
{% endblock %} {% block js %}
{{ parent() }}
{{ vite_entry_script_tags("mod_docgen_picktemplate") }}
{{ vite_entry_script_tags("mod_entity_workflow_pick") }}
{{ vite_entry_script_tags("mod_document_action_buttons_group") }}
{{ encore_entry_script_tags("mod_docgen_picktemplate") }}
{{ encore_entry_script_tags("mod_entity_workflow_pick") }}
{{ encore_entry_script_tags("mod_document_action_buttons_group") }}
{% endblock %} {% block css %}
{{ parent() }}
{{ vite_entry_script_tags("mod_docgen_picktemplate") }}
{{ vite_entry_link_tags("mod_entity_workflow_pick") }}
{{ vite_entry_link_tags("mod_document_action_buttons_group") }}
{{ encore_entry_script_tags("mod_docgen_picktemplate") }}
{{ encore_entry_link_tags("mod_entity_workflow_pick") }}
{{ encore_entry_link_tags("mod_document_action_buttons_group") }}
{% endblock %} {% block content %}
<div class="document-list">
<h1>{{ "Documents" }}</h1>

View File

@@ -13,14 +13,14 @@ License * along with this program. If not, see <http://www.gnu.org/licenses/>.
{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}
{% endblock %} {% block js %}
{{ parent() }}
{{ vite_entry_script_tags("mod_docgen_picktemplate") }}
{{ vite_entry_script_tags("mod_entity_workflow_pick") }}
{{ vite_entry_script_tags("mod_document_action_buttons_group") }}
{{ encore_entry_script_tags("mod_docgen_picktemplate") }}
{{ encore_entry_script_tags("mod_entity_workflow_pick") }}
{{ encore_entry_script_tags("mod_document_action_buttons_group") }}
{% endblock %} {% block css %}
{{ parent() }}
{{ vite_entry_link_tags("mod_docgen_picktemplate") }}
{{ vite_entry_link_tags("mod_entity_workflow_pick") }}
{{ vite_entry_link_tags("mod_document_action_buttons_group") }}
{{ encore_entry_link_tags("mod_docgen_picktemplate") }}
{{ encore_entry_link_tags("mod_entity_workflow_pick") }}
{{ encore_entry_link_tags("mod_document_action_buttons_group") }}
{% endblock %} {% block content %}
<div class="document-list">

View File

@@ -58,9 +58,9 @@
{% endblock %}
{% block js %}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@@ -54,9 +54,9 @@
{% endblock %}
{% block js %}
{{ vite_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_async_upload') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_async_upload') }}
{% endblock %}

View File

@@ -24,11 +24,11 @@
{% block title %}{{ 'Detail of document of %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %}
{% block js %}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}

View File

@@ -7,21 +7,21 @@
<link rel="shortcut icon" href="{{ asset('build/images/favicon.ico') }}" type="image/x-icon">
<title>Signature</title>
{{ vite_entry_link_tags('mod_bootstrap') }}
{{ vite_entry_link_tags('mod_forkawesome') }}
{{ vite_entry_link_tags('chill') }}
{{ vite_entry_link_tags('vue_document_signature') }}
{{ encore_entry_link_tags('mod_bootstrap') }}
{{ encore_entry_link_tags('mod_forkawesome') }}
{{ encore_entry_link_tags('chill') }}
{{ encore_entry_link_tags('vue_document_signature') }}
</head>
<body>
{% block js %}
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
<script type="text/javascript">
window.signature = {{ signature|json_encode|raw }};
</script>
{{ vite_entry_script_tags('vue_document_signature') }}
{{ encore_entry_script_tags('vue_document_signature') }}
{% endblock %}
<div class="content" id="content">

View File

@@ -2,12 +2,12 @@
{% block css %}
{{ parent() }}
{{ vite_entry_link_tags('mod_document_download_button') }}
{{ encore_entry_link_tags('mod_document_download_button') }}
{% endblock %}
{% block js %}
{{ parent() }}
{{ vite_entry_script_tags('mod_document_download_button') }}
{{ encore_entry_script_tags('mod_document_download_button') }}
{% endblock %}
{% block title %}{{ 'workflow.public_link.title'|trans }} - {{ title }}{% endblock %}

View File

@@ -15,7 +15,10 @@ use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoterInterface;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowAttachment;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelperInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Security;
@@ -34,7 +37,8 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
public function __construct(
private readonly Security $security,
private readonly ?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null,
private readonly EntityWorkflowAttachmentRepository $entityWorkflowAttachmentRepository,
private readonly WorkflowRelatedEntityPermissionHelperInterface $workflowDocumentService,
) {}
public function supports(StoredObjectRoleEnum $attribute, StoredObject $subject): bool
@@ -46,16 +50,6 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
public function voteOnAttribute(StoredObjectRoleEnum $attribute, StoredObject $subject, TokenInterface $token): bool
{
// we first try to get the permission from the workflow, as attachement (this is the less intensive query)
$workflowPermissionAsAttachment = match ($attribute) {
StoredObjectRoleEnum::SEE => $this->workflowDocumentService->isAllowedByWorkflowForReadOperation($subject),
StoredObjectRoleEnum::EDIT => $this->workflowDocumentService->isAllowedByWorkflowForWriteOperation($subject),
};
if (WorkflowRelatedEntityPermissionHelper::FORCE_DENIED === $workflowPermissionAsAttachment) {
return false;
}
// Retrieve the related entity
$entity = $this->getRepository()->findAssociatedEntityToStoredObject($subject);
@@ -65,7 +59,7 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
$regularPermission = $this->security->isGranted($voterAttribute, $entity);
if (!$this->canBeAssociatedWithWorkflow()) {
return $regularPermission;
return $this->voteOnStoredObjectAsAttachementOfAWorkflow($attribute, $regularPermission, $subject);
}
$workflowPermission = match ($attribute) {
@@ -74,9 +68,41 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface
};
return match ($workflowPermission) {
WorkflowRelatedEntityPermissionHelper::FORCE_GRANT => true,
WorkflowRelatedEntityPermissionHelper::FORCE_DENIED => false,
WorkflowRelatedEntityPermissionHelper::ABSTAIN => WorkflowRelatedEntityPermissionHelper::FORCE_GRANT === $workflowPermissionAsAttachment || $regularPermission,
WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT => true,
WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED => false,
WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN => $this->voteOnStoredObjectAsAttachementOfAWorkflow($attribute, $regularPermission, $subject),
};
}
private function voteOnStoredObjectAsAttachementOfAWorkflow(StoredObjectRoleEnum $attribute, bool $regularPermission, StoredObject $storedObject): bool
{
$attachments = $this->entityWorkflowAttachmentRepository->findByStoredObject($storedObject);
// we get all the entity workflows where the stored object is attached
$entityWorkflows = array_map(static fn (EntityWorkflowAttachment $attachment) => $attachment->getEntityWorkflow(), $attachments);
// we compute all the permission for each entity workflow
$permissions = array_map(fn (EntityWorkflow $entityWorkflow): string => match ($attribute) {
StoredObjectRoleEnum::SEE => $this->workflowDocumentService->isAllowedByWorkflowForReadOperation($entityWorkflow),
StoredObjectRoleEnum::EDIT => $this->workflowDocumentService->isAllowedByWorkflowForWriteOperation($entityWorkflow),
}, $entityWorkflows);
// now, we reduce the permissions: abstain are ignored. Between DENIED and and GRANT, DENIED takes precedence
$computedPermission = WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN;
foreach ($permissions as $permission) {
if (WorkflowRelatedEntityPermissionHelperInterface::FORCE_DENIED === $permission) {
return false;
}
if (WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT === $permission) {
$computedPermission = WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT;
}
}
if (WorkflowRelatedEntityPermissionHelperInterface::ABSTAIN === $computedPermission) {
return $regularPermission;
}
// this is the case where WorkflowRelatedEntityPermissionHelperInterface::FORCE_GRANT is returned
return true;
}
}

View File

@@ -16,6 +16,7 @@ use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository;
use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Symfony\Component\Security\Core\Security;
@@ -25,8 +26,9 @@ final class AccompanyingCourseDocumentStoredObjectVoter extends AbstractStoredOb
private readonly AccompanyingCourseDocumentRepository $repository,
Security $security,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
EntityWorkflowAttachmentRepository $attachmentRepository,
) {
parent::__construct($security, $workflowDocumentService);
parent::__construct($security, $attachmentRepository, $workflowDocumentService);
}
protected function getRepository(): AssociatedEntityToStoredObjectInterface

View File

@@ -16,6 +16,7 @@ use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface;
use Chill\DocStoreBundle\Repository\PersonDocumentRepository;
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper;
use Symfony\Component\Security\Core\Security;
@@ -25,8 +26,9 @@ class PersonDocumentStoredObjectVoter extends AbstractStoredObjectVoter
private readonly PersonDocumentRepository $repository,
Security $security,
WorkflowRelatedEntityPermissionHelper $workflowDocumentService,
EntityWorkflowAttachmentRepository $attachmentRepository,
) {
parent::__construct($security, $workflowDocumentService);
parent::__construct($security, $attachmentRepository, $workflowDocumentService);
}
protected function getRepository(): AssociatedEntityToStoredObjectInterface

Some files were not shown because too many files have changed in this diff Show More