Compare commits

...

172 Commits

Author SHA1 Message Date
611a968162 Duplicate and accompanying course evaluation document
- create a service which duplicate the accompanying course work evaluation document
- create a controller to duplicate this document
- update the vuejs component to use this duplicate action
2024-09-23 16:32:47 +02:00
ce80207d98 Create route for duplicating a accompanying course document 2024-09-23 14:36:02 +02:00
5fc5369db6 in constructor for AccompanyingCourseDocumentRepository.php, do not create a property 2024-09-23 14:32:59 +02:00
20e8b03588 Rewrite the Component PickWorkflow.vue into typescript 2024-09-23 14:32:59 +02:00
4b65ec9b54 Create a duplicator service for accompanying course document 2024-09-23 14:32:40 +02:00
a8c5d1f660 Remove unused constructor parameter 2024-09-19 17:48:34 +02:00
5f67a7aadc Create a service to duplicate a storedObject into another one 2024-09-19 17:48:03 +02:00
77d06d756a Block document editing if any signature associated to a workflow is signed
Add a check in `WorkflowStoredObjectPermissionHelper` to block document editing once any signature is signed. Accompanied by new tests to verify this behavior.
2024-09-19 16:18:16 +02:00
c4c5c860f0 Merge branch 'signature-app/wp-576-restorestored-object-version' into 'signature-app-master'
See the list of stored object and restore some versions

See merge request Chill-Projet/chill-bundles!733
2024-09-19 13:36:29 +00:00
47f575de92 Enhance version restoration and download features
Introduce a version restoration button and logic to track restored versions throughout the UI. Update download buttons to display action strings conditionally and implement toast notifications for version restoration.
2024-09-19 13:42:23 +02:00
5906171041 Add restoration functionality for stored object versions
Introduce a service to restore stored object versions along with relevant tests and an API endpoint. This includes database migrations for version relationships, enhancing stored object version tracking.
2024-09-19 13:42:23 +02:00
b0e2e65885 Add document history button with modal viewer
This commit introduces a History button to the DocumentActionButtonsGroup component to view document versions. It includes new components for the modal dialog and API integrations to fetch and display version histories. This feature allows users to view and restore previous versions of stored objects.
2024-09-19 13:42:22 +02:00
dd3f6fb0ab Enhance StoredObjectVersion normalization
Add UserNormalizer dependency and pass createdAt context for createdBy normalization, ensuring compatibility with nullable context groups. This improves the accuracy and completeness of the normalized data.
2024-09-19 13:42:21 +02:00
5fa5a2349e Add FileIcon.vue and refactor DropFile.vue to use it
Introduced `FileIcon.vue` to handle file type icons centrally. Refactored `DropFile.vue` to utilize the new `FileIcon` component, improving code clarity and maintainability.
2024-09-19 13:42:20 +02:00
48f727dcfd Update vue version to ^3.5.6 2024-09-19 13:42:20 +02:00
6a0e26ec31 Add point-in-time normalization to stored object versions
Introduced a new normalizer for StoredObjectPointInTime and updated the StoredObjectVersionNormalizer to include point-in-time data when specified in the context. Added corresponding test cases to ensure the new normalization logic works correctly.
2024-09-19 13:42:19 +02:00
943a42cd38 Add StoredObjectVersionApiController and corresponding test
Added a new class StoredObjectVersionApiController in ChillDocGeneratorBundle which lists versions of a specified stored object. Corresponding unit test has been added as well. Made modifications in `StoredObject.php` to make the versions selectable. Also updated the API specifications to include a new GET route for retrieving versions.
2024-09-19 13:42:18 +02:00
d9b36533a2 Fix the query to find staled entity workflows
Add a test to check that the query still works
2024-09-19 12:31:46 +02:00
3697aee584 Merge branch '307-permission-apply-all-transitions' into 'signature-app-master'
Create a permission to apply all transitions

Closes #307

See merge request Chill-Projet/chill-bundles!729
2024-09-17 07:52:43 +00:00
33cc308e1e Merge branch 'upgrade-sf5' into signature-app-master 2024-09-16 15:30:01 +02:00
7206e13984 Merge branch 'master' into upgrade-sf5 2024-09-16 15:29:43 +02:00
6f28d154c8 Fix referrers display to show only current referrers.
Updated the view to loop through current referrers in the accompanying period. Added new method `getReferrersHistoryCurrent` to the entity to filter and return only active referrers, ensuring correct display in the UI. Also included documentation for better code clarity.
2024-09-16 15:25:25 +02:00
4d8de46ac9 Apply the voter to allow all transition on EntityWorkflowGuardTransition
This allow to effectively check that a user is allowed to apply all transitions on a workflow and, if yes, enable the given transition.
2024-09-16 14:47:00 +02:00
4696332a46 Create a voter for applying all transitions on all workflow's steps
This voter checks that the related entity's centers is reachable by the user.
2024-09-16 14:42:37 +02:00
0d54637d35 Add missing constructor argument in SignatureStepStateChangerTest 2024-09-16 13:19:14 +02:00
7a7d1d5b16 remove blank file 2024-09-16 12:13:52 +02:00
e5737b0c49 remove temporary method 2024-09-16 11:51:58 +02:00
45323e9136 Merge remote-tracking branch 'origin/upgrade-sf5' into signature-app-master 2024-09-16 11:51:33 +02:00
9f1afb8423 Add access controls and permissions for signature steps
Implemented a Voter to enforce permissions on signature steps, ensuring only authorized users can sign steps. Updated relevant controllers and templates to reflect these permissions, and added corresponding tests to validate the changes.
2024-09-13 17:04:57 +02:00
1494c7ecd7 Merge branch 'signature-app/add-manual-zone' into 'signature-app-master'
Improve signature app

See merge request Chill-Projet/chill-bundles!725
2024-09-13 14:23:44 +00:00
911dfc2878 fix rector errors 2024-09-13 16:22:09 +02:00
8e984f2006 do not allow to sign if the signature is already applyied 2024-09-13 16:16:42 +02:00
f0e8df38af remove the left-arrow on the "retour" button, because it was placed on the right of the page 2024-09-13 16:03:06 +02:00
1c0d334b91 downgrade symfony/event-dispatcher-contracts to version 2.4
This is necessary for using some dependencies which only works with symfony 5.4
2024-09-12 17:34:28 +02:00
nobohan
59c34dabd7 Signature: allow for null index in signature zone 2024-09-12 17:18:13 +02:00
nobohan
119668e415 Signature: allow for null index in signature zone 2024-09-12 17:02:45 +02:00
nobohan
2b516629f6 Signature: refresh document after signature 2024-09-12 17:02:08 +02:00
nobohan
092b5c4f90 Signature: get the stored object back in the check signature API 2024-09-12 15:26:03 +02:00
nobohan
ae1459cf77 Signature: topbar UI 2024-09-12 14:22:58 +02:00
nobohan
57d2929ecd Signature: move buttons to a top toolbar + change behavior on a new zone 2024-09-12 14:03:43 +02:00
bc34d84d63 Merge remote-tracking branch 'origin/master' into upgrade-sf5 2024-09-12 13:36:50 +02:00
f0f651edea update cs after php-cs-fixer upgrade 2024-09-12 12:02:33 +02:00
nobohan
3c987e0b8d Signature: keep selected zone when turning pages 2024-09-12 11:31:31 +02:00
f8a986d59b Add user IP and authenticated user details to signature
Updated the SignatureRequest metadata to include the requester's IP address and currently authenticated user details. Also improved the rendering of signer information by leveraging the `ChillEntityRenderManagerInterface`.
2024-09-12 11:18:35 +02:00
09563979a2 Refactor entity rendering with manager pattern
Introduce ChillEntityRenderManager to centralize entity rendering logic, reducing redundancy and improving code organization. Update dependencies and service configuration to support the new manager pattern, enhancing maintainability and flexibility of entity rendering in templates.
2024-09-12 11:18:35 +02:00
nobohan
0ee91800ab Merge branch 'signature-app/add-manual-zone' of https://gitlab.com/Chill-Projet/chill-bundles into signature-app/add-manual-zone 2024-09-12 10:46:52 +02:00
nobohan
d08212df46 Signature: add and process returnPath in the signature app 2024-09-12 09:46:14 +02:00
nobohan
4933238f3f Signature - improve UI signature app 2024-09-12 09:46:14 +02:00
nobohan
c23568032c Signature: add a signature zone manually 2024-09-12 09:46:13 +02:00
18af2ca70b Handle null transitionBy and improve display logic
Added checks for null transitionBy cases in workflow templates to display "Automated transition" when applicable. Also improved conditional rendering for 'destUser' and 'ccUser' fields to avoid empty elements.
2024-09-11 21:52:34 +02:00
f1505a9d15 Add locale to workflow URLs in notification templates
This is required to send notification within a console command
2024-09-11 21:16:54 +02:00
4e588ed0e0 Add logging to SignatureStepStateChanger
Enhanced the SignatureStepStateChanger by integrating a LoggerInterface to provide detailed logging at key points in the state transition process. This includes informational messages when marking signatures or skipping transitions, as well as debug messages when determining the next steps.
2024-09-11 21:14:07 +02:00
70671dadac Refactor workflow guard logic and add internal methods
Removed guard logic from EntityWorkflowTransitionEventSubscriber and created a new EntityWorkflowGuardTransition class for separation of concerns. Marked several setter methods in EntityWorkflowStepSignature as internal to guide proper usage. Added comprehensive tests to ensure the new guard logic functions correctly.
2024-09-11 21:13:58 +02:00
5dfbdad13d Release 2.24.0 2024-09-11 14:31:52 +02:00
b3e2d4ff9f Merge branch '306-invalidate-downloaded-document' into 'master'
Remove documents from memory after download

Closes #306

See merge request Chill-Projet/chill-bundles!727
2024-09-11 12:29:37 +00:00
01c2848a83 Fix deprecated method in redis 2024-09-11 14:23:23 +02:00
d0ee381627 Upgrade of php-cs-fixer 2024-09-11 14:21:32 +02:00
8b1b255050 Remove documents from memory after download
Implemented functionality to remove documents from browser memory 45 seconds after they are converted or downloaded. This ensures that clicking the download button again re-downloads the document. The reset state function was added to both ConvertButton.vue and DownloadButton.vue components.
2024-09-11 13:22:49 +02:00
f0d581b7f8 Merge branch '291_workflow_pdfsignedmessagehandler' into 'signature-app-master'
Lorsque tous les usagers ont signé un workflow, le workflow retourne à l’envoyeur avec une étape « workflow signé »

See merge request Chill-Projet/chill-bundles!726
2024-09-11 07:23:51 +00:00
nobohan
1197a46f5f Refactor PDF signature handling and add signature state changer
Simplified PdfSignedMessageHandler by delegating signature state changes to a new SignatureStepStateChanger class. Added utility method to EntityWorkflowStepSignature for checking pending signatures and created new test cases for the SignatureStepStateChanger.
2024-09-10 21:27:55 +02:00
00e878892e Merge branch '305-convert-to-pdf-on-signature-step' into 'signature-app-master'
Convert a document to pdf when an entity workflow arrives in a signature step

See merge request Chill-Projet/chill-bundles!724
2024-09-10 18:42:10 +00:00
941444b7d5 Add event subscriber to convert docs to PDF before signature
Introduce ConvertToPdfBeforeSignatureStepEventSubscriber to convert documents to PDF when reaching a signature step in the workflow. Includes tests to ensure the conversion process only triggers when necessary.
2024-09-10 17:48:32 +02:00
a60ea0e066 Add StoredObjectToPdfConverter service and unit tests
Introduced the StoredObjectToPdfConverter service to handle conversion of stored objects to PDF format. Added unit tests to ensure proper functionality, including versioning and exception handling.
2024-09-10 17:48:32 +02:00
1ddd283f26 Add signer type differentiation for workflows
Added a method to determine if the signer is a 'person' or 'user'. Updated the signature template to handle both types accordingly, ensuring the correct entity type is displayed in workflow signatures.
2024-09-10 17:48:32 +02:00
669b967899 Enhance object version removal to exclude point-in-time versions
Add a check to exclude versions associated with points in time before deleting old object versions. This ensures that such versions are not mistakenly removed, providing greater data integrity. Updated tests and repository methods accordingly.
2024-09-10 17:48:31 +02:00
d33da6519a Add StoredObjectPointInTime entity and related functionality
Implemented a new StoredObjectPointInTime entity to manage snapshots of stored objects. This includes related migrations, enum for reasons, repository, and integration with StoredObjectVersion.
2024-09-10 17:48:31 +02:00
f5ba5d574b Add WopiConverter service and update Collabora integration tests
Introduce the WopiConverter service to handle document-to-PDF conversion using Collabora Online. Extend and update related tests in WopiConvertToPdfTest and ConvertControllerTest for better coverage and reliability. Enhance the GitLab CI configuration to exclude new test category "collabora-integration".
2024-09-10 17:48:31 +02:00
ccc11b1c1d Merge branch '295-cancel-workflow-after-90-days' into 'signature-app-master'
Create CancelStaleWorkflow message, handler and cronjob

See merge request Chill-Projet/chill-bundles!720
2024-09-09 13:27:12 +00:00
2fb46c65c2 Refactor CancelStaleWorkflowCronJobTest to simplify setup
Replaced KernelTestCase with TestCase to simplify test setup and removed dependency on the database connection. Added NullLogger to replace mocked LoggerInterface during testing. Updated method call in tests to correctly reference CancelStaleWorkflowMessage class.
2024-09-09 15:16:10 +02:00
f4356ac249 Add test for detecting stale workflows and enhance handler
Added a new test to check if workflows are stale in EntityWorkflowTest. Enhanced CancelStaleWorkflowHandler to handle stale workflows more accurately, including checking if workflows have transitioned recently. Updated EntityWorkflow entity to cascade remove workflow steps.

Refactor tests for handler, to avoid using $kernel during tests
2024-09-09 15:08:39 +02:00
d152efe084 Refactor imports and remove redundant type strings
This commit refactors the usage of \DateTimeImmutable to ensure consistent namespacing and removes unnecessary string type declarations from constants in CancelStaleWorkflowCronJob. These changes improve code readability and maintainability.
2024-09-09 14:58:19 +02:00
ee9530d03f More conditions to find staled workflows 2024-09-09 10:46:35 +02:00
b97eabf0d2 Get workflowComponent directly from registry 2024-09-09 10:46:35 +02:00
2e69d2df90 Adjust test to work with actual workflow + minor fix of handler logic 2024-09-09 10:46:33 +02:00
cb446edd18 Suffix message class with 'Message' and add check on workflow to assert no transitions were applied since message placed in queue 2024-09-09 10:40:42 +02:00
5d84e997c1 Php cs fixes 2024-09-09 10:40:42 +02:00
35199b6993 Create test for CancelStaleWorkflowHandler: wip state 2024-09-09 10:40:42 +02:00
dab68fb409 Add CancelStaleWorkflowCronJobTest 2024-09-09 10:40:41 +02:00
6001bb6447 Add logger messages for possible debugging purposes 2024-09-09 10:40:41 +02:00
29fec50515 Add cronjob and repository method to find and cancel stale workflows every other day 2024-09-09 10:40:41 +02:00
34edb02cd0 Create message and handler for canceling stale workflows 2024-09-09 10:40:41 +02:00
860ae5cedf Create CancelStaleWorkflow message and handler 2024-09-09 10:40:40 +02:00
bf056046ab Fix cs 2024-09-06 14:40:25 +02:00
4d73f9b81a Rename Convert to ConvertController for clarity
Renamed Convert class and relevant references to ConvertController to improve clarity and maintain consistency. Updated corresponding test files and route configurations to reflect the new name.
2024-09-06 14:07:51 +02:00
dd159f4379 Merge branch '297-workflow-en-attente' into 'signature-app-master'
Allow user to put workflow on hold

See merge request Chill-Projet/chill-bundles!718
2024-09-06 12:02:40 +00:00
49ad25b4c8 Refactor WorkflowOnHoldController and improve tests
Refactored WorkflowOnHoldController to remove dependencies and improve redirect handling. Updated test cases to use PHPUnit instead of KernelTestCase and mock proper dependencies. Added relationship handling in EntityWorkflowStep to manage EntityWorkflowStepHold instances accurately.
2024-09-06 14:02:11 +02:00
ad94310981 Refactor workflow hold functionality to avoid relying on database to perform some checks on "user holds entityworkflow"
Simplify the logic in handling workflow on hold status by moving related checks and operations to `EntityWorkflowStep` and `EntityWorkflow` entities. This includes implementing new methods to check if a step or workflow is held by a specific user and refactoring the controller actions to use these methods.
2024-09-05 20:46:29 +02:00
e8f09b507f Fix cs after php-cs-fixer upgrade, fix phpstan and rector errors 2024-09-05 18:00:37 +02:00
e29e1db6ed Take into account 'destUserByAccessKey' in the list of workflows associated to a user
Refactor the query to include checks for user membership via both 'destUser' and 'destUserByAccessKey'. This ensures that workflows correctly account for user access by multiple criteria.
2024-09-05 17:38:18 +02:00
8c4f342ca1 Correct instantiation of controller within test 2024-09-05 17:19:28 +02:00
745a29f742 Adjust logic for removing the hold on a workflow only by user who owns the hold and when a transition is applied on the workflow 2024-09-05 17:19:27 +02:00
41ffc470a0 Adjust test to check creation of onHold if user is allowed to apply a transition 2024-09-05 17:19:27 +02:00
46b31ae1ea Adjust logic to only allow on hold if user is allowed to apply a transition 2024-09-05 17:19:26 +02:00
8c5e94e295 Work on test for workflowOnHold controller 2024-09-05 17:19:25 +02:00
9c8a84cdbd Add test for WorkflowOnHoldControllerTest 2024-09-05 17:19:24 +02:00
a82b99aecc Add template-extends on EntityWorkflowStepHoldRepository 2024-09-05 17:19:23 +02:00
deb4bda16e Add unique constraint as attribute on EntityWorkflowStepHold class 2024-09-05 17:19:23 +02:00
c1e5f4a57e Move onHold methods to a separate WorkflowOnHold controller 2024-09-05 17:19:20 +02:00
6fc5a10dc4 Add unique constraint to migration 2024-09-05 17:18:43 +02:00
18abc84e68 Rector fixes 2024-09-05 17:18:43 +02:00
e85c31826f php cs fixes 2024-09-05 17:18:42 +02:00
d119ba49f7 Add on_hold label to vue components 2024-09-05 17:18:42 +02:00
c21de777fd Place on_hold label next to breadcrumb in twig template 2024-09-05 17:18:42 +02:00
15eaf648df Add label to workflow listing and history to indicate whether it's on hold 2024-09-05 17:18:42 +02:00
42471269db Implement logic to put workflow on hold and resume it 2024-09-05 17:16:18 +02:00
9475a708c3 Add EntityWorkflowStepHold entity to allow workflow to be put on hold by user
Entity created, migration, and repository.
2024-09-05 17:13:20 +02:00
bf1af1aaad Merge branch '301-has-signed-statement' into 'signature-app-master'
Adjust behavior when signature in signed state

See merge request Chill-Projet/chill-bundles!717
2024-09-05 14:50:05 +00:00
8ea87053f0 fix some tests 2024-09-05 16:47:45 +02:00
nobohan
479a02bbc7 Signature: add and process returnPath in the signature app 2024-09-05 14:11:57 +02:00
nobohan
0d62d8d1c6 Signature - improve UI signature app 2024-09-05 11:52:11 +02:00
nobohan
5b90632231 Signature: add a signature zone manually 2024-09-05 11:52:08 +02:00
3c9ee41b3b fix some tests 2024-09-04 18:30:18 +02:00
d0031e82e8 Add hover effect and slim class to dev assets and apply in signature list
Introduced a new SCSS file to handle hover effects on rows and added the ability to remove bottom margins with a "slim" class. Updated various twig templates to utilize these new styles for better visual feedback and alignment.
2024-09-04 17:55:01 +02:00
20f2bc6c35 Enhance signature display with detailed person information
Updated the signature view template to include person details using the '_insert_vue_onthefly.html.twig' template. This change adds more contextual information about the signer, such as their name and status, improving the user experience.
2024-09-04 17:26:46 +02:00
71d3aa3969 Refactor signature rendering logic
Reorganized the signature rendering loop for better readability. Moved the row alignment inside the loop and added text alignment for signed statements. Simplified the conditional checks within the loop to enhance code maintainability.
2024-09-04 17:24:11 +02:00
ce781a5b58 Translate datetime object with icu: split date and time
Translate datetime within icu format
2024-09-04 17:14:43 +02:00
2dd275a074 Merge branch '296-signature-menu-tab' into 'signature-app-master'
Add person menu entry for signature  list

See merge request Chill-Projet/chill-bundles!719
2024-09-04 15:13:14 +00:00
5f5d4b8f06 Add person menu entry for signature list 2024-09-04 15:13:14 +00:00
cc8214d52c Add flash message in case signature was already applied 2024-09-04 17:08:38 +02:00
0c797c2997 Redirect to workflow show page if document already signed
Verify the state of the signature. If isSigned is true, redirection to
workflow show page.
2024-09-04 17:08:37 +02:00
ee6edba206 Create isSigned method in EntityWorkflowStepSignature.php
Refactorization and ease of use in template and workflow controller
2024-09-04 17:08:35 +02:00
3e6d764b9b Replace sign button with signed statement if person/user has signed 2024-09-04 17:06:45 +02:00
3e5a558cdf Add exists method to RemoveOldVersionMessageHandlerTest
Introduce the exists method to handle checks for StoredObject or StoredObjectVersion in test cases. This modification ensures consistency and proper exception handling in the testing framework.
2024-09-04 15:18:07 +02:00
0e6b7d76a4 Add exists method to WebdavControllerTest
Included a new method `exists` to handle existence checks for StoredObject or StoredObjectVersion within WebdavControllerTest. This method currently always returns true, ensuring initial compatibility and providing a foundation for future logic refinements.
2024-09-04 15:10:18 +02:00
b2042bd1e4 Merge branch 'signature-app/object-version' into 'signature-app-master'
Add versioning to stored objects

See merge request Chill-Projet/chill-bundles!710
2024-09-04 12:46:43 +00:00
6e9f111fd9 Fix syntax errors in RemoveExpiredStoredObjectCronJob class
Correct syntax errors involving constant definitions in the RemoveExpiredStoredObjectCronJob class. This change ensures compliance with PHP's constant declaration standards.
2024-09-04 14:45:17 +02:00
313fb9ffdf PHP CS Fixer updated (3.63.1 -> v3.64.0) 2024-09-04 14:38:56 +02:00
063bc2857f Remove deprecated constants from StoredObjectNormalizer
Deleted the deprecated constants `ADD_DAV_SEE_LINK_CONTEXT` and `ADD_DAV_EDIT_LINK_CONTEXT` from the `StoredObjectNormalizer` class. These constants are no longer in use and their removal cleans up the codebase.
2024-09-04 14:34:49 +02:00
615629d1b4 Simplify entity relationship and enforce foreign key constraints
Removed the resetStoredObject() method call from StoredObject, adjusted the storedObjectId column in the stored_object_version table to be NOT NULL, and moved the association setup of the StoredObject entity directly into the constructor in StoredObjectVersion. This ensures that every StoredObjectVersion has a valid StoredObject and maintains database integrity.
2024-09-04 14:28:13 +02:00
667e144681 Add PDF signature zone availability checks
Introduce `PDFSignatureZoneAvailable` service to check available PDF signature zones. Updated `WorkflowAddSignatureController` to use the new service. Added unit tests to verify the correctness of the functionality.
2024-09-04 14:09:53 +02:00
e17203ca3a Add PDF signature zone availability checks
Introduce `PDFSignatureZoneAvailable` service to check available PDF signature zones. Updated `WorkflowAddSignatureController` to use the new service. Added unit tests to verify the correctness of the functionality.
2024-09-04 13:55:08 +02:00
c6a6d76790 Add signatureZoneIndex to PdfSignedMessage and related classes
Included signatureZoneIndex for PdfSignedMessage in class definitions, handlers, and serializers to support signature zones. Updated test cases to reflect this new property, ensuring robust validation for handling and serialization.
2024-09-03 15:44:25 +02:00
3d49c959e0 Update DropFile to handle object versioning 2024-09-03 15:42:04 +02:00
5d0b531820 Upgrade chill-bundles to v3.1.0 2024-08-30 10:59:04 +02:00
5be3cae288 Merge branch 'add_household_to_activity_list_export' into 'upgrade-sf5'
Add household info to activity exports

See merge request Chill-Projet/chill-bundles!721
2024-08-30 08:57:27 +00:00
4587f66402 Add household info to activity exports 2024-08-30 08:57:27 +00:00
b6edbb3eed Refactor StoredObject normalization handling
Deprecate and remove specific context constants from StoredObjectNormalizer. Update object properties for better clarity and add permissions handling. Introduce related tests and adjust other files relying on the old context constants.
2024-08-28 23:19:24 +02:00
00cc3b7806 Refactor backend for getting signed url 2024-08-28 18:00:20 +02:00
7ab52ff09e Add stored object creation endpoint
Introduced a new API endpoint to create stored objects with access control for roles 'ROLE_ADMIN' and 'ROLE_USER'. Updated corresponding routes, removed unused dependencies, and added unit tests to ensure functionality.
2024-08-28 15:34:42 +02:00
2d82c1e105 rector fixes after rector's upgrade 2024-08-28 15:34:13 +02:00
e477a49c92 Integrate SwaggerUI with direct download and cleanup package
Added a customized SwaggerUI HTML template under Dev directory. Removed outdated swagger-ui dependency from package.json to streamline dependency management.
2024-08-28 15:26:19 +02:00
0db2652f08 Add cron job for removing expired stored objects
Introduced `RemoveExpiredStoredObjectCronJob` to automate the deletion of expired stored objects every 7 days. Enhanced associated tests and updated relevant interfaces and classes to support the new cron job functionality.
2024-08-28 14:06:11 +02:00
c38f7c1179 Add functionality to delete old versions of documents
This commit introduces a feature that automatically deletes old versions of StoredObjects in the Chill application. A cron job, "RemoveOldVersionCronJob", has been implemented to delete versions older than 90 days. A message handler, "RemoveOldVersionMessageHandler", has been added to handle deletion requests. Furthermore, unit tests for the new functionality have been provided.
2024-08-28 14:06:10 +02:00
67d24cb951 Use "createdAt" from database to compute the last modified datetime in StoredObjectManager
The code has been updated to use 'createdAt' from StoredObjectVersion entity in StoredObjectManager. Specifically, if a 'createdAt' datetime is set, we return that datetime. This change also includes corresponding test cases to validate the functionality. The situation helps deal with files created before July 2024.
2024-08-28 14:06:09 +02:00
cb90261309 Update random_bytes length in filename and prefix generation
The size of the random byte string used in the generateFilename method of StoredObjectVersion has been reduced from 16 to 8. Conversely, the size of the random byte string used in the generatePrefix method of StoredObject has been increased from 8 to 32.

The naming generation fit better with the usage, as 16bytes are generated for each file (more version), and less for the version.
2024-08-28 14:06:09 +02:00
2feea24c41 Add Collabora configuration guide and NullProofValidator class
A new document detailing the configuration steps for enabling Collabora in development has been added. This includes setting up ngrok and configuring both the Collabora and Symfony servers. Furthermore, a new class, NullProofValidator, has been created for validation during the development process. This class always returns true, making it useful for debugging purposes.
2024-08-28 14:06:08 +02:00
1b16d4fe3b Flush entities when storing document using webdav / put operation
The WebdavController has been updated to flush the EntityManager after writing a document, while its tests have been adjusted correspondingly. A new test for the document PUT operation has also been added, which ensures the EntityManager flushes and the StoredObjectManager writes to this document.
2024-08-28 14:06:08 +02:00
ce5659219a Fix test 2024-08-28 14:06:07 +02:00
5fefe09a39 Fix test 2024-08-28 14:06:07 +02:00
e21db73b84 Refactor and simplify document management functionality to adapt to StoredObject versioning
This commit includes several updates to the document management functionality within ChillWopiBundle and ChillDocGeneratorBundle, refactoring for simplicity and improved readability.
2024-08-28 14:06:07 +02:00
3978ea9a47 Update StoredObjectManager to handle versioned StoredObjects
The StoredObjectManager and related test cases have been updated to handle versioned StoredObjects, allowing the same methods to work with either a StoredObject or its versions. The changes also involve return information for the write method and enhancements to the write test procedure. This provides more functionality and flexibility for handling StoredObjects in different versions.
2024-08-28 14:06:06 +02:00
4fbb7811ac Refactor StoredObjectDataMapper to use registerVersion method
Removed saveHistory and set methods in StoredObjectDataMapper and replaced them with one call to registerVersion.
2024-08-28 14:06:06 +02:00
2b7ea4178b Add versioning to stored objects
This update introduces a versioning system to the stored objects in the ChillDocStoreBundle. The 'StoredObject' entity now includes several new methods, and maintains a collection of 'StoredObjectVersion' instances. Each time a 'StoredObject' is modified, a new version instance is created and added to the collection, ensuring a history of changes. Migration file for the addition of new database column included. Corresponding tests are also updated.
2024-08-28 14:06:06 +02:00
2bef3c3878 french translation for the version 2.23.0 [ci-skip] 2024-07-19 15:32:45 +02:00
cea44d1788 Release 2.23.0 2024-07-19 14:03:53 +02:00
84069e03dc Add filename display on file upload
This update introduces a new feature to the DropFile component; now filenames are displayed when they are uploaded. This provides a user-friendly way to view the file being managed. Additionally, some styling adjustments were made to accommodate this new addition.
2024-07-19 13:55:22 +02:00
ad5e780936 Do not update the createdAt column when importing postal code which does not change
The conflict resolution clause in the SQL command of the PostalCodeBaseImporter service has been updated. It now only changes the 'updatedAt' timestamp if either the 'center' position or the 'label' actually differs from the existing entry. This ensures that the 'updatedAt' field reflects when meaningful changes occurred.
2024-07-19 13:42:48 +02:00
19accc4d00 Handle duplicate addresses in AddressReferenceBaseImporter
Refactored the AddressReferenceBaseImporter to optimize address import and reconciliation. The code now identifies duplicate addresses in the temporary table and handles them according to the 'allowRemoveDoubleRefId' flag. This enhances data consistency during import operations.
2024-07-19 13:41:17 +02:00
6cb085f5f7 fix cs 2024-07-19 13:39:36 +02:00
97239ada84 More documentation for cronjob 2024-07-18 10:09:12 +02:00
643156f822 Merge branch 'issue271_account_acp_closing_date' into 'master'
#271 Account for acp closing date inn action filters (export)

See merge request Chill-Projet/chill-bundles!707
2024-07-05 13:42:06 +00:00
ff0b205591 Merge branch '273-notif-all-read' into 'master'
added unread and read all function with endpoints for notifications

See merge request Chill-Projet/chill-bundles!671
2024-07-05 13:36:31 +00:00
2d67843901 added unread and read all function with endpoints for notifications 2024-07-05 13:36:31 +00:00
2b09e1459c Merge branch '274-active-status-filter' into 'master'
Resolve "Add active/inactive filter to user list in admin"

Closes #274

See merge request Chill-Projet/chill-bundles!694
2024-07-05 08:52:46 +00:00
029524ba2c Resolve "Add active/inactive filter to user list in admin" 2024-07-05 08:52:46 +00:00
fa91e9494d Merge branch 'issue123_duplicate_calendar_range_by_week' into 'master'
Add a button to duplicate calendar ranges from a week to another one

See merge request Chill-Projet/chill-bundles!706
2024-07-05 08:07:49 +00:00
4e72d6fea1 Update slot duration in calendar
The slot duration in the 'MyCalendarRange' module has been updated to a new time. The previous duration was 5 minutes, but it has now been increased to 15 minutes to provide users with longer time slots.
2024-07-05 10:01:09 +02:00
5666b8b647 Expand range of calendar weeks in App2.vue to get weeks int the future and in the past
The code has been altered to increase the range of weeks computed from 15 to 30, with a modification to the 'getMonday' method accordingly. This enhances the user calendar experience by providing a wider time array to choose from.
2024-07-05 09:58:49 +02:00
nobohan
0573f56782 copy week in my calendar - improve layout 2024-07-03 11:35:33 +02:00
nobohan
3bee18b0fa #271 Account for acp closing date inn action filters (export) 2024-07-02 16:31:18 +02:00
nobohan
843698a1d8 DX vuejs code style 2024-07-01 15:39:52 +02:00
nobohan
499640e48b Add a button to duplicate calendar ranges from a week to another one 2024-07-01 15:33:39 +02:00
531 changed files with 11096 additions and 2551 deletions

View File

@@ -0,0 +1,6 @@
kind: Fixed
body: Show only the current referrer in the page "show" for an accompanying period
workf
time: 2024-09-16T15:18:43.017401122+02:00
custom:
Issue: "308"

View File

@@ -1,11 +1,30 @@
## v2.23.0 - 2024-07-23
## v2.23.0 - 2024-07-23 & 2024-07-19
### Feature
* ([#221](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/221)) [DX] move async-upload-bundle features into chill-bundles
* Add job bundle (module emploi)
* ([#221](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/221)) [DX] move async-upload-bundle features into chill-bundles
* Add job bundle (module emploi)
* Upgrade import of address list to the last version of compiled addresses of belgian-best-address
* Upgrade CKEditor and refactor configuration with use of typescript
* ([#123](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/123)) Add a button to duplicate calendar ranges from a week to another one
* [admin] filter users by active / inactive in the admin user's list
* ([#273](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/273)) Add the possibility to mark all notifications as read
* Handle duplicate reference id in the import of reference addresses
* Do not update the "createdAt" column when importing postal code which does not change
* Display filename on file upload within the UI interface
### Fixed
* Fix resolving of centers for an household, which will fix in turn the access control
* Resolved type hinting error in activity list export
* Fix resolving of centers for an household, which will fix in turn the access control
* Resolved type hinting error in activity list export
* ([#271](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/271)) Take into account the acp closing date in the acp works date filter
### Traduction française des principaux changements
- Ajout d'un bouton pour dupliquer les périodes de disponibilités d'une semaine à une autre;
- dans l'interface d'administration, filtre sur les utilisateurs actifs. Par défaut, seul les utilisateurs
actifs sont affichés;
- Nouveau bouton pour indiquer toutes les notifications comme lues;
- Améliorations sur l'import des adresses et des codes postaux;
- Affiche le nom du fichier déposé quand on téléverse un fichier depuis le poste de travail local;
- Agrandit l'icône du type de fichier dans l'interface de dépôt de fichier;
- correction: tient compte de la date de fermeture du parcours dans les filtres sur les actions d'accompagnement.

3
.changes/v2.24.0.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.24.0 - 2024-09-11
### Feature
* ([#306](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/306)) When a document is converted or downloaded in the browser, this document is removed from the browser memory after 45s. Future click on the button re-download the document.

3
.changes/v3.1.0.md Normal file
View File

@@ -0,0 +1,3 @@
## v3.1.0 - 2024-08-30
### Feature
* Add export aggregator to aggregate activities by household + filter persons that are not part of an accompanyingperiod during a certain timeframe.

2
.env
View File

@@ -23,7 +23,7 @@ TRUSTED_HOSTS='^(localhost|example\.com|nginx)$'
###< symfony/framework-bundle ###
## Wopi server for editing documents online
WOPI_SERVER=http://collabora:9980
EDITOR_SERVER=http://collabora:9980
# must be manually set in .env.local
# ADMIN_PASSWORD=

View File

@@ -41,3 +41,5 @@ DATABASE_URL="postgresql://postgres:postgres@db:5432/test?serverVersion=14&chars
ASYNC_UPLOAD_TEMP_URL_KEY=
ASYNC_UPLOAD_TEMP_URL_BASE_PATH=
ASYNC_UPLOAD_TEMP_URL_CONTAINER=
EDITOR_SERVER=https://localhost:9980

View File

@@ -122,7 +122,7 @@ unit_tests:
- php tests/console chill:db:sync-views --env=test
- php -d memory_limit=2G tests/console cache:clear --env=test
- php -d memory_limit=3G tests/console doctrine:fixtures:load -n --env=test
- php -d memory_limit=4G bin/phpunit --colors=never --exclude-group dbIntensive
- php -d memory_limit=4G bin/phpunit --colors=never --exclude-group dbIntensive,openstack-integration,collabora-integration
artifacts:
expire_in: 1 day
paths:

View File

@@ -6,33 +6,62 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v3.1.0 - 2024-08-30
### Feature
* Add export aggregator to aggregate activities by household + filter persons that are not part of an accompanyingperiod during a certain timeframe.
## v3.0.0 - 2024-08-26
### Fixed
* Fix delete action for accompanying periods in draft state
* Fix connection to azure when making an calendar event in chill
* CollectionType js fixes for remove button and adding multiple entries
* Fix delete action for accompanying periods in draft state
* Fix connection to azure when making an calendar event in chill
* CollectionType js fixes for remove button and adding multiple entries
## v2.23.0 - 2024-07-23
## v2.24.0 - 2024-09-11
### Feature
* ([#221](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/221)) [DX] move async-upload-bundle features into chill-bundles
* Add job bundle (module emploi)
* Upgrade import of address list to the last version of compiled addresses of belgian-best-address
* Upgrade CKEditor and refactor configuration with use of typescript
* ([#306](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/306)) When a document is converted or downloaded in the browser, this document is removed from the browser memory after 45s. Future click on the button re-download the document.
## v2.23.0 - 2024-07-19 & 2024-07-23
### Feature
* ([#123](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/123)) Add a button to duplicate calendar ranges from a week to another one
* [admin] filter users by active / inactive in the admin user's list
* ([#273](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/273)) Add the possibility to mark all notifications as read
* Handle duplicate reference id in the import of reference addresses
* Do not update the "createdAt" column when importing postal code which does not change
* Display filename on file upload within the UI interface
### Fixed
* Fix resolving of centers for an household, which will fix in turn the access control
* Resolved type hinting error in activity list export
* ([#271](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/271)) Take into account the acp closing date in the acp works date filter
### Traduction française des principaux changements
- Ajout d'un bouton pour dupliquer les périodes de disponibilités d'une semaine à une autre;
- dans l'interface d'administration, filtre sur les utilisateurs actifs. Par défaut, seul les utilisateurs
actifs sont affichés;
- Nouveau bouton pour indiquer toutes les notifications comme lues;
- Améliorations sur l'import des adresses et des codes postaux;
- Affiche le nom du fichier déposé quand on téléverse un fichier depuis le poste de travail local;
- Agrandit l'icône du type de fichier dans l'interface de dépôt de fichier;
- correction: tient compte de la date de fermeture du parcours dans les filtres sur les actions d'accompagnement.
* ([#221](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/221)) [DX] move async-upload-bundle features into chill-bundles
* Add job bundle (module emploi)
* Upgrade import of address list to the last version of compiled addresses of belgian-best-address
* Upgrade CKEditor and refactor configuration with use of typescript
### Fixed
* Fix resolving of centers for an household, which will fix in turn the access control
* Resolved type hinting error in activity list export
## v2.22.2 - 2024-07-03
### Fixed
* Remove scope required for event participation stats
* Remove scope required for event participation stats
## v2.22.1 - 2024-07-01
### Fixed
* Remove debug word
* Remove debug word
### DX
* Add a command for reading official address DB from Luxembourg and update chill addresses
* Add a command for reading official address DB from Luxembourg and update chill addresses
## v2.22.0 - 2024-06-25
### Feature
@@ -75,7 +104,7 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.20.1 - 2024-06-05
### Fixed
* Do not allow StoredObjectCreated for edit and convert buttons
* Do not allow StoredObjectCreated for edit and convert buttons
## v2.20.0 - 2024-06-05
### Fixed
@@ -122,96 +151,96 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.18.2 - 2024-04-12
### Fixed
* ([#250](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/250)) Postal codes import : fix the source URL and the keys to handle each record
* ([#250](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/250)) Postal codes import : fix the source URL and the keys to handle each record
## v2.18.1 - 2024-03-26
### Fixed
* Fix layout issue in document generation for admin (minor)
* Fix layout issue in document generation for admin (minor)
## v2.18.0 - 2024-03-26
### Feature
* ([#268](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/268)) Improve admin UX to configure document templates for document generation
* ([#268](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/268)) Improve admin UX to configure document templates for document generation
### Fixed
* ([#267](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/267)) Fix the join between job and user in the user list (admin): show only the current user job
* ([#267](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/267)) Fix the join between job and user in the user list (admin): show only the current user job
## v2.17.0 - 2024-03-19
### Feature
* ([#237](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/237)) New export filter for social actions with an evaluation created between two dates
* ([#258](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/258)) In the list of accompangying period, add the list of person's centers and the duration of the course
* ([#238](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/238)) Allow to customize list person with new fields
* ([#237](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/237)) New export filter for social actions with an evaluation created between two dates
* ([#258](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/258)) In the list of accompangying period, add the list of person's centers and the duration of the course
* ([#238](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/238)) Allow to customize list person with new fields
* ([#159](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/159)) Admin can publish news on the homepage
### Fixed
* ([#264](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/264)) Fix languages: load the languages in all availables languages configured for Chill
* ([#259](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/259)) Keep a consistent behaviour between the filtering of activities within the document generation (model "accompanying period with activities"), and the same filter in the list of activities for an accompanying period
* ([#264](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/264)) Fix languages: load the languages in all availables languages configured for Chill
* ([#259](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/259)) Keep a consistent behaviour between the filtering of activities within the document generation (model "accompanying period with activities"), and the same filter in the list of activities for an accompanying period
## v2.16.3 - 2024-02-26
### Fixed
* ([#236](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/236)) Fix translation of user job -> 'service' must be 'métier'
* ([#236](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/236)) Fix translation of user job -> 'service' must be 'métier'
### UX
* ([#232](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/232)) Order user jobs and services alphabetically in export filters
* ([#232](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/232)) Order user jobs and services alphabetically in export filters
## v2.16.2 - 2024-02-21
### Fixed
* Check for null values in closing motive of parcours d'accompagnement for correct rendering of template
* Check for null values in closing motive of parcours d'accompagnement for correct rendering of template
## v2.16.1 - 2024-02-09
### Fixed
* Force bootstrap version to avoid error in builds with newer version
* Force bootstrap version to avoid error in builds with newer version
## v2.16.0 - 2024-02-08
### Feature
* ([#231](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/231)) Create new filter for persons having a participation in an accompanying period during a certain time span
* ([#241](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/241)) [Export][List of accompanyign period] Add two columns: the list of persons participating to the period, and their ids
* ([#244](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/244)) Add capability to generate export about change of steps of accompanying period, and generate exports for this
* ([#253](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/253)) Export: group accompanying period by person participating
* ([#243](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/243)) Export: add filter for courses not linked to a reference address
* ([#229](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/229)) Allow to group activities linked with accompanying period by reason
* ([#115](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/115)) Prevent social work to be saved when another user edited conccurently the social work
* Modernize the event bundle, with some new fields and multiple improvements
* ([#231](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/231)) Create new filter for persons having a participation in an accompanying period during a certain time span
* ([#241](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/241)) [Export][List of accompanyign period] Add two columns: the list of persons participating to the period, and their ids
* ([#244](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/244)) Add capability to generate export about change of steps of accompanying period, and generate exports for this
* ([#253](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/253)) Export: group accompanying period by person participating
* ([#243](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/243)) Export: add filter for courses not linked to a reference address
* ([#229](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/229)) Allow to group activities linked with accompanying period by reason
* ([#115](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/115)) Prevent social work to be saved when another user edited conccurently the social work
* Modernize the event bundle, with some new fields and multiple improvements
### Fixed
* ([#220](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/220)) Fix error in logs about wrong typing of eventArgs in onEditNotificationComment method
* ([#256](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/256)) Fix the conditions upon which social actions should be optional or required in relation to social issues within the activity creation form
* ([#220](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/220)) Fix error in logs about wrong typing of eventArgs in onEditNotificationComment method
* ([#256](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/256)) Fix the conditions upon which social actions should be optional or required in relation to social issues within the activity creation form
### UX
* ([#260](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/260)) Order list of centers alphabetically in dropdown 'user' section admin.
* ([#260](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/260)) Order list of centers alphabetically in dropdown 'user' section admin.
## v2.15.2 - 2024-01-11
### Fixed
* Fix the id_seq used when creating a new accompanying period participation during fusion of two person files
* Fix the id_seq used when creating a new accompanying period participation during fusion of two person files
### DX
* Set placeholder to False for expanded EntityType form fields where required is set to False.
* Set placeholder to False for expanded EntityType form fields where required is set to False.
## v2.15.1 - 2023-12-20
### Fixed
* Fix the household export query to exclude accompanying periods that are in draft state.
* Fix the household export query to exclude accompanying periods that are in draft state.
### DX
* ([#167](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/167)) Fixed readthedocs compilation by updating readthedocs config file and requirements for Sphinx
* ([#167](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/167)) Fixed readthedocs compilation by updating readthedocs config file and requirements for Sphinx
## v2.15.0 - 2023-12-11
### Feature
* ([#191](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/191)) Add export "number of household associate with an exchange"
* ([#235](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/235)) Export: add dates on the filter "filter course by activity type"
* ([#191](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/191)) Add export "number of household associate with an exchange"
* ([#235](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/235)) Export: add dates on the filter "filter course by activity type"
### Fixed
* ([#214](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/214)) Fix error when posting an empty comment on an accompanying period.
* ([#233](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/233)) Fix "filter evaluation by evaluation type" (and add select2 to the list of evaluation types to pick)
* ([#214](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/214)) Fix error when posting an empty comment on an accompanying period.
* ([#233](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/233)) Fix "filter evaluation by evaluation type" (and add select2 to the list of evaluation types to pick)
* ([#234](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/234)) Fix "filter aside activity by date"
* ([#228](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/228)) Fix export of activity for people created before the introduction of the createdAt column on person (during v1)
* ([#246](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/246)) Do not show activities, evaluations and social work when associated to a confidential accompanying period, except for the users which are allowed to see them
* ([#228](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/228)) Fix export of activity for people created before the introduction of the createdAt column on person (during v1)
* ([#246](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/246)) Do not show activities, evaluations and social work when associated to a confidential accompanying period, except for the users which are allowed to see them
## v2.14.1 - 2023-11-29
### Fixed
* Export: fix list person with custom fields
* ([#100](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/100)) Add a paginator to budget elements (resource and charge types) in the admin
* Fix error in ListEvaluation when "handling agents" are alone
* Export: fix list person with custom fields
* ([#100](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/100)) Add a paginator to budget elements (resource and charge types) in the admin
* Fix error in ListEvaluation when "handling agents" are alone
## v2.14.0 - 2023-11-24
### Feature
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
### Fixed
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
* Fix various errors in custom fields administration
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
* Fix various errors in custom fields administration
## v2.13.0 - 2023-11-21
### Feature
@@ -225,7 +254,7 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.12.1 - 2023-11-16
### Fixed
* ([#208](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/208)) Export: fix loading of form for "filter action by type, goal and result"
* ([#208](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/208)) Export: fix loading of form for "filter action by type, goal and result"
## v2.12.0 - 2023-11-15
### Feature
@@ -256,36 +285,36 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.11.0 - 2023-11-07
### Feature
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
### Fixed
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
* Fix "group activity by creator job" aggregator
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
* Fix "group activity by creator job" aggregator
## v2.10.6 - 2023-11-07
### Fixed
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix aggregator by geographical unit on person: avoid inconsistencies
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix aggregator by geographical unit on person: avoid inconsistencies
## v2.10.5 - 2023-11-05
### Fixed
* ([#183](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/183)) Fix "problem during download" on some filters, which used a wrong data type
* ([#184](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/184)) Fix filter "activity by date"
* ([#183](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/183)) Fix "problem during download" on some filters, which used a wrong data type
* ([#184](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/184)) Fix filter "activity by date"
## v2.10.4 - 2023-10-26
### Fixed
* Fix null value constraint errors when merging relationships in doubles
* Fix null value constraint errors when merging relationships in doubles
## v2.10.3 - 2023-10-26
### Fixed
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Replace old method of getting translator with injection of translatorInterface
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Replace old method of getting translator with injection of translatorInterface
## v2.10.2 - 2023-10-26
### Fixed
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Use injection of translator instead of ->get().
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Use injection of translator instead of ->get().
## v2.10.1 - 2023-10-24
### Fixed
* Fix export controller when generating an export without any data in session
* Fix export controller when generating an export without any data in session
## v2.10.0 - 2023-10-24
### Feature
@@ -310,11 +339,11 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.9.2 - 2023-10-17
### Fixed
* Fix possible null values in string's entities
* Fix possible null values in string's entities
## v2.9.1 - 2023-10-17
### Fixed
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers
## v2.9.0 - 2023-10-17
### Feature
@@ -362,57 +391,57 @@ But if you do not need this any more, you must ensure that the configuration key
## v2.7.0 - 2023-09-27
### Feature
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
### Fixed
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"
## v2.6.3 - 2023-09-19
### Fixed
* Remove id property from document
mappedsuperclass
* Remove id property from document
mappedsuperclass
## v2.6.2 - 2023-09-18
### Fixed
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.
## v2.6.1 - 2023-09-14
### Fixed
* Filter out active centers in exports, which uses a different PickCenterType.
* Filter out active centers in exports, which uses a different PickCenterType.
## v2.6.0 - 2023-09-14
### Feature
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Add locations in Aside Activity. By default, suggest user location, otherwise a select with all locations.
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Adapt Aside Activity exports: display location, filter by location, group by location
* Use the CRUD controller for center entity + add the isActive property to be able to mask instances of Center that are no longer in use.
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Add locations in Aside Activity. By default, suggest user location, otherwise a select with all locations.
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Adapt Aside Activity exports: display location, filter by location, group by location
* Use the CRUD controller for center entity + add the isActive property to be able to mask instances of Center that are no longer in use.
### Fixed
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) reinstate the fusion of duplicate persons
* Missing translation in Work Actions exports
* Reimplement the mission type filter on tasks, only for instances that have a config parameter indicating true for this.
* ([#135](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/135)) Corrects a typing error in 2 filters, which caused an
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) reinstate the fusion of duplicate persons
* Missing translation in Work Actions exports
* Reimplement the mission type filter on tasks, only for instances that have a config parameter indicating true for this.
* ([#135](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/135)) Corrects a typing error in 2 filters, which caused an
error when trying to reedit a saved export
* ([#136](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/136)) [household] when moving a person to a sharing position to a not-sharing position on the same household on the same date, remove the previous household membership on the same household. This fix duplicate member.
* ([#136](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/136)) [household] when moving a person to a sharing position to a not-sharing position on the same household on the same date, remove the previous household membership on the same household. This fix duplicate member.
* Add missing translation for comment field placeholder in repositionning household editor.
* Do not send an email to creator twice when adding a comment to a notification
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) Fix gestion doublon functionality to work with chill bundles v2
* Do not send an email to creator twice when adding a comment to a notification
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) Fix gestion doublon functionality to work with chill bundles v2
### UX
* Uniformize badge-person in household banner (background, size)
## v2.5.3 - 2023-07-20
### Fixed
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
## v2.5.2 - 2023-07-15
### Fixed
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
## v2.5.1 - 2023-07-14
### Fixed
* [collate addresses] block collating addresses to another address reference where the address reference is already the best match
* [collate addresses] block collating addresses to another address reference where the address reference is already the best match
## v2.5.0 - 2023-07-14
### Feature

View File

@@ -43,6 +43,7 @@
"symfony/dom-crawler": "^5.4",
"symfony/error-handler": "^5.4",
"symfony/event-dispatcher": "^5.4",
"symfony/event-dispatcher-contracts": "^2.4",
"symfony/expression-language": "^5.4",
"symfony/filesystem": "^5.4",
"symfony/finder": "^5.4",

View File

@@ -39,9 +39,12 @@ Implements a :code:`Chill\MainBundle\Cron\CronJobInterface`. Here is an example:
use Chill\MainBundle\Entity\CronJobExecution;
use DateInterval;
use DateTimeImmutable;
use Symfony\Component\Clock\ClockInterface;
class MyCronJob implements CronJobInterface
{
function __construct(private ClockInterface $clock) {}
public function canRun(?CronJobExecution $cronJobExecution): bool
{
// the parameter $cronJobExecution contains data about the last execution of the cronjob
@@ -56,7 +59,7 @@ Implements a :code:`Chill\MainBundle\Cron\CronJobInterface`. Here is an example:
// this cron job should be executed if the last execution is greater than one day, but only during the night
$now = new DateTimeImmutable('now');
$now = $clock->now();
return $cronJobExecution->getLastStart() < $now->sub(new DateInterval('P1D'))
&& in_array($now->format('H'), self::ACCEPTED_HOURS, true)
@@ -69,10 +72,15 @@ Implements a :code:`Chill\MainBundle\Cron\CronJobInterface`. Here is an example:
return 'arbitrary-and-unique-key';
}
public function run(): void
public function run(array $lastExecutionData): void
{
// here, we execute the command
}
// we return execution data, which will be served for next execution
// this data should be easily serializable in a json column: it should contains
// only int, string, etc. Avoid storing object
return ['last-execution-id' => 0];
}
}
How are cron job scheduled ?

View File

@@ -0,0 +1,125 @@
Enable CODE for development
===========================
For editing a document, there must be a way to communicate between the collabora server and the symfony server, in
both direction. The domain name should also be the same for collabora server and for the browser which access to the
online editor.
Using ngrok (or other http tunnel)
----------------------------------
One can configure a tunnel server to expose your local install to the web, and access to your local server using the
tunnel url.
Start ngrok
^^^^^^^^^^^
This can be achieve using `ngrok <https://ngrok.com/>`_.
.. note::
The configuration of ngrok is outside of the scope of this document. Refers to the ngrok's documentation.
.. code-block:: bash
# ensuring that your server is running through http and port 8000
ngrok http 8000
# then open the link given by the ngrok utility and you should reach your app
At this step, ensure that you can reach your local app using the ngrok url.
Configure Collabora
^^^^^^^^^^^^^^^^^^^
The collabora server must be executed online and configure to access to your ngrok installation. Ensure that the aliasgroup
exists for your ngrok application (`See the CODE documentation: <https://sdk.collaboraonline.com/docs/installation/Configuration.html#multihost-configuration>`_).
Configure your app
^^^^^^^^^^^^^^^^^^
Set the :code:`EDITOR_SERVER` variable to point to your collabora server, this should be done in your :code:`.env.local` file.
At this point, everything must be fine. In case of errors, watch the log from your collabora server, use the `profiler <https://symfony.com/doc/current/profiler.html>`_
to debug the requests.
.. note::
In case of error while validating proof (you'll see those message in the collabora's logs), you can temporarily disable
the proof validation adding this code snippet in `config/services.yaml`:
.. code-block:: yaml
when@dev:
# add only in dev environment, to avoid security problems
services:
ChampsLibres\WopiLib\Contract\Service\ProofValidatorInterface:
# this class will always validate proof
alias: Chill\WopiBundle\Service\Wopi\NullProofValidator
With a local CODE image
-----------------------
.. warning::
This configuration is not sure, and must be refined. The documentation does not seems to be entirely valid.
Use a local domain name and https for your app
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use the proxy feature from embedded symfony server to run your app. `See the dedicated doc <https://symfony.com/doc/current/setup/symfony_server.html#local-domain-names>`
Configure also the `https certificate <https://symfony.com/doc/current/setup/symfony_server.html#enabling-tls>`_
In this example, your local domain name will be :code:`my-domain` and the url will be :code:`https://my-domain.wip`.
Ensure that the proxy is running.
Create a certificate database for collabora
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Collabora must validate your certificate generated by symfony console. For that, you need `to create a NSS database <https://sdk.collaboraonline.com/docs/installation/Configuration.html#validating-digital-signatures>`
and configure collabora to use it.
At first, export the certificate for symfony development. Use the graphical interface from your browser to get the
certificate as a PEM file.
.. code-block:: bash
# create your database in a custom directory
mkdir /path/to/your/directory
certutil -N -d /path/to/your/directory
cat /path/to/your/ca.crt | certutil -d . -A symfony -t -t C,P,C,u,w -a
Launch CODE properly configured
.. code-block:: yaml
collabora:
image: collabora/code:latest
environment:
- SLEEPFORDEBUGGER=0
- DONT_GEN_SSL_CERT="True"
# add path to the database
- extra_params=--o:ssl.enable=false --o:ssl.termination=false --o:logging.level=7 -o:certificates.database_path=/etc/custom-certificates/nss-database
- username=admin
- password=admin
- dictionaries=en_US
- aliasgroup1=https://my-domain.wip
ports:
- "127.0.0.1:9980:9980"
volumes:
- "/path/to/your/directory/nss-database:/etc/custom-certificates/nss-database"
extra_hosts:
- "my-domain.wip:host-gateway"
Configure your app
^^^^^^^^^^^^^^^^^^
Into your :code:`.env.local` file:
.. code-block:: env
EDITOR_SERVER=http://${COLLABORA_HOST}:${COLLABORA_PORT}
At this step, you should be able to edit a document through collabora.

View File

@@ -54,9 +54,8 @@
"masonry-layout": "^4.2.2",
"mime": "^4.0.0",
"pdfjs-dist": "^4.3.136",
"swagger-ui": "^4.15.5",
"vis-network": "^9.1.0",
"vue": "^3.2.37",
"vue": "^3.5.6",
"vue-i18n": "^9.1.6",
"vue-multiselect": "3.0.0-alpha.2",
"vue-toast-notification": "^3.1.2",

View File

@@ -68,7 +68,7 @@ final class ActivityController extends AbstractController
private readonly FilterOrderHelperFactoryInterface $filterOrderHelperFactory,
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly PaginatorFactory $paginatorFactory,
private readonly ChillSecurity $security
private readonly ChillSecurity $security,
) {}
/**

View File

@@ -28,7 +28,7 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
public function __construct(
protected ActivityReasonCategoryRepository $activityReasonCategoryRepository,
protected ActivityReasonRepository $activityReasonRepository,
protected TranslatableStringHelper $translatableStringHelper
protected TranslatableStringHelper $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -26,7 +26,7 @@ class ActivityUsersJobAggregator implements AggregatorInterface
public function __construct(
private readonly UserJobRepositoryInterface $userJobRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -26,7 +26,7 @@ class ActivityUsersScopeAggregator implements AggregatorInterface
public function __construct(
private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -26,7 +26,7 @@ class CreatorJobAggregator implements AggregatorInterface
public function __construct(
private readonly UserJobRepositoryInterface $userJobRepository,
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -26,7 +26,7 @@ class CreatorScopeAggregator implements AggregatorInterface
public function __construct(
private readonly ScopeRepository $scopeRepository,
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -0,0 +1,99 @@
<?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\ActivityBundle\Export\Aggregator\PersonAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Repository\Household\HouseholdRepository;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final readonly class HouseholdAggregator implements AggregatorInterface
{
public function __construct(private HouseholdRepository $householdRepository) {}
public function buildForm(FormBuilderInterface $builder)
{
// nothing to add here
}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, mixed $data)
{
return function (int|string|null $value): string|int {
if ('_header' === $value) {
return 'export.aggregator.person.by_household.household';
}
if ('' === $value || null === $value || null === $household = $this->householdRepository->find($value)) {
return '';
}
return $household->getId();
};
}
public function getQueryKeys($data)
{
return ['activity_household_agg'];
}
public function getTitle()
{
return 'export.aggregator.person.by_household.title';
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$qb->join(
HouseholdMember::class,
'activity_household_agg_household_member',
Join::WITH,
$qb->expr()->andX(
$qb->expr()->eq('activity_household_agg_household_member.person', 'activity.person'),
$qb->expr()->lte('activity_household_agg_household_member.startDate', 'activity.date'),
$qb->expr()->orX(
$qb->expr()->gte('activity_household_agg_household_member.endDate', 'activity.date'),
$qb->expr()->isNull('activity_household_agg_household_member.endDate')
)
)
);
$qb->join(
Household::class,
'activity_household_agg_household',
Join::WITH,
$qb->expr()->eq('activity_household_agg_household_member.household', 'activity_household_agg_household')
);
$qb
->addSelect('activity_household_agg_household.id AS activity_household_agg')
->addGroupBy('activity_household_agg');
}
public function applyOn()
{
return Declarations::ACTIVITY_PERSON;
}
}

View File

@@ -19,6 +19,7 @@ use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\DBAL\Exception\InvalidArgumentException;
use Doctrine\ORM\EntityManagerInterface;
@@ -44,6 +45,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
'person_firstname',
'person_lastname',
'person_id',
'household_id',
];
private readonly bool $filterStatsByCenters;
@@ -189,19 +191,26 @@ class ListActivity implements ListInterface, GroupedExportInterface
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
// throw an error if any fields are present
// throw an error if no fields are present
if (!\array_key_exists('fields', $data)) {
throw new InvalidArgumentException('Any fields have been checked.');
throw new InvalidArgumentException('No fields have been checked.');
}
$qb = $this->entityManager->createQueryBuilder();
$qb
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'actperson');
->join('activity.person', 'person')
->join(
HouseholdMember::class,
'householdmember',
Query\Expr\Join::WITH,
'person = householdmember.person AND householdmember.startDate <= activity.date AND (householdmember.endDate IS NULL OR householdmember.endDate > activity.date)'
)
->join('householdmember.household', 'household');
if ($this->filterStatsByCenters) {
$qb->join('actperson.centerHistory', 'centerHistory');
$qb->join('person.centerHistory', 'centerHistory');
$qb->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
@@ -224,17 +233,22 @@ class ListActivity implements ListInterface, GroupedExportInterface
break;
case 'person_firstname':
$qb->addSelect('actperson.firstName AS person_firstname');
$qb->addSelect('person.firstName AS person_firstname');
break;
case 'person_lastname':
$qb->addSelect('actperson.lastName AS person_lastname');
$qb->addSelect('person.lastName AS person_lastname');
break;
case 'person_id':
$qb->addSelect('actperson.id AS person_id');
$qb->addSelect('person.id AS person_id');
break;
case 'household_id':
$qb->addSelect('household.id AS household_id');
break;
@@ -284,7 +298,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
return ActivityStatsVoter::LISTS;
}
public function supportsModifiers()
public function supportsModifiers(): array
{
return [
Declarations::ACTIVITY,

View File

@@ -42,7 +42,7 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
/**
* The action for this report.
*/
protected string $action = 'sum'
protected string $action = 'sum',
) {
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}

View File

@@ -39,7 +39,7 @@ class ListActivityHelper
private readonly TranslatorInterface $translator,
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly TranslatableStringExportLabelHelper $translatableStringLabelHelper,
private readonly UserHelper $userHelper
private readonly UserHelper $userHelper,
) {}
public function addSelect(QueryBuilder $qb): void

View File

@@ -73,7 +73,7 @@ final readonly class PeriodHavingActivityBetweenDatesFilter implements FilterInt
$qb->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.Activity::class." {$alias} WHERE {$alias}.date >= :{$from} AND {$alias}.date < :{$to} AND {$alias}.accompanyingPeriod = activity.accompanyingPeriod"
'SELECT 1 FROM '.Activity::class." {$alias} WHERE {$alias}.date >= :{$from} AND {$alias}.date < :{$to} AND {$alias}.accompanyingPeriod = acp"
)
);

View File

@@ -25,7 +25,7 @@ final readonly class ActivityPresenceFilter implements FilterInterface
{
public function __construct(
private TranslatableStringHelperInterface $translatableStringHelper,
private TranslatorInterface $translator
private TranslatorInterface $translator,
) {}
public function getTitle()

View File

@@ -26,7 +26,7 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
{
public function __construct(
protected TranslatableStringHelperInterface $translatableStringHelper,
protected ActivityTypeRepositoryInterface $activityTypeRepository
protected ActivityTypeRepositoryInterface $activityTypeRepository,
) {}
public function addRole(): ?string

View File

@@ -39,7 +39,7 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
public function alterQuery(QueryBuilder $qb, $data): void
{
// create a subquery for activity
$sqb = $qb->getEntityManager()->createQueryBuilder();
@@ -121,7 +121,7 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
];
}
public function describeAction($data, $format = 'string')
public function describeAction($data, $format = 'string'): array
{
return [
[] === $data['reasons'] ?
@@ -141,7 +141,7 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
];
}
public function getTitle()
public function getTitle(): string
{
return 'export.filter.activity.person_between_dates.title';
}

View File

@@ -29,7 +29,7 @@ class UsersJobFilter implements FilterInterface
public function __construct(
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly UserJobRepositoryInterface $userJobRepository
private readonly UserJobRepositoryInterface $userJobRepository,
) {}
public function addRole(): ?string

View File

@@ -29,7 +29,7 @@ class UsersScopeFilter implements FilterInterface
public function __construct(
private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -59,7 +59,7 @@ class ActivityType extends AbstractType
protected TranslatableStringHelper $translatableStringHelper,
protected array $timeChoices,
protected SocialIssueRender $socialIssueRender,
protected SocialActionRender $socialActionRender
protected SocialActionRender $socialActionRender,
) {
if (!$tokenStorage->getToken()->getUser() instanceof User) {
throw new \RuntimeException('you should have a valid user');

View File

@@ -27,7 +27,7 @@ class PickActivityReasonType extends AbstractType
public function __construct(
private readonly ActivityReasonRepository $activityReasonRepository,
private readonly ActivityReasonRender $reasonRender,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function configureOptions(OptionsResolver $resolver)

View File

@@ -32,7 +32,7 @@ final readonly class ActivityDocumentACLAwareRepository implements ActivityDocum
private EntityManagerInterface $em,
private CenterResolverManagerInterface $centerResolverManager,
private AuthorizationHelperForCurrentUserInterface $authorizationHelperForCurrentUser,
private Security $security
private Security $security,
) {}
public function buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface

View File

@@ -25,7 +25,7 @@ class ActivityReasonRepository extends ServiceEntityRepository
{
public function __construct(
ManagerRegistry $registry,
private readonly RequestStack $requestStack
private readonly RequestStack $requestStack,
) {
parent::__construct($registry, ActivityReason::class);
}

View File

@@ -24,7 +24,7 @@ class ActivityStoredObjectVoter extends AbstractStoredObjectVoter
public function __construct(
private readonly ActivityRepository $repository,
Security $security,
WorkflowStoredObjectPermissionHelper $workflowDocumentService
WorkflowStoredObjectPermissionHelper $workflowDocumentService,
) {
parent::__construct($security, $workflowDocumentService);
}

View File

@@ -75,7 +75,7 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
public function __construct(
protected Security $security,
VoterHelperFactoryInterface $voterHelperFactory
VoterHelperFactoryInterface $voterHelperFactory,
) {
$this->voterHelper = $voterHelperFactory->generate(self::class)
->addCheckFor(Person::class, [self::SEE, self::CREATE])

View File

@@ -50,7 +50,7 @@ class ActivityContext implements
private readonly TranslatorInterface $translator,
private readonly BaseContextData $baseContextData,
private readonly ThirdPartyRender $thirdPartyRender,
private readonly ThirdPartyRepository $thirdPartyRepository
private readonly ThirdPartyRepository $thirdPartyRepository,
) {}
public function adminFormReverseTransform(array $data): array

View File

@@ -56,7 +56,7 @@ class ListActivitiesByAccompanyingPeriodContext implements
private readonly SocialIssueRepository $socialIssueRepository,
private readonly ThirdPartyRepository $thirdPartyRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly UserRepository $userRepository
private readonly UserRepository $userRepository,
) {}
public function adminFormReverseTransform(array $data): array

View File

@@ -76,7 +76,7 @@ final class TranslatableActivityReasonTest extends TypeTestCase
*/
protected function getTranslatableStringHelper(
$locale = 'en',
$fallbackLocale = 'en'
$fallbackLocale = 'en',
) {
$prophet = new \Prophecy\Prophet();
$requestStack = $prophet->prophesize();

View File

@@ -138,7 +138,7 @@ final class ActivityVoterTest extends KernelTestCase
Scope $scope,
Center $center,
$attribute,
$message
$message,
) {
$token = $this->prepareToken($user);
$activity = $this->prepareActivity($scope, $this->preparePerson($center));

View File

@@ -32,7 +32,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
protected EntityManagerInterface $em,
protected AuthorizationHelperInterface $helper,
TokenStorageInterface $storage,
protected ActivityACLAwareRepository $aclAwareRepository
protected ActivityACLAwareRepository $aclAwareRepository,
) {
if (!$storage->getToken()->getUser() instanceof User) {
throw new \RuntimeException('A user should be authenticated !');

View File

@@ -243,3 +243,7 @@ services:
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\PersonAggregator:
tags:
- { name: chill.export_aggregator, alias: activity_person_agg }
Chill\ActivityBundle\Export\Aggregator\PersonAggregators\HouseholdAggregator:
tags:
- { name: chill.export_aggregator, alias: activity_household_agg }

View File

@@ -428,6 +428,9 @@ export:
by_person:
title: Grouper les échanges par usager (dossier d'usager dans lequel l'échange est enregistré)
person: Usager
by_household:
title: Grouper les échanges par ménage
household: Identifiant ménage
acp:
by_activity_type:
title: Grouper les parcours par type d'échange

View File

@@ -25,7 +25,7 @@ final class AsideActivityController extends CRUDController
{
public function __construct(
private readonly AsideActivityCategoryRepository $categoryRepository,
private readonly Security $security
private readonly Security $security,
) {}
public function createEntity(string $action, Request $request): object
@@ -76,7 +76,7 @@ final class AsideActivityController extends CRUDController
string $action,
$query,
Request $request,
PaginatorInterface $paginator
PaginatorInterface $paginator,
) {
if ('index' === $action) {
return $query->orderBy('e.date', 'DESC');

View File

@@ -22,7 +22,7 @@ class ByActivityTypeAggregator implements AggregatorInterface
{
public function __construct(
private readonly AsideActivityCategoryRepository $asideActivityCategoryRepository,
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -26,7 +26,7 @@ class ByUserJobAggregator implements AggregatorInterface
public function __construct(
private readonly UserJobRepositoryInterface $userJobRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -26,7 +26,7 @@ class ByUserScopeAggregator implements AggregatorInterface
public function __construct(
private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -41,7 +41,7 @@ final readonly class ListAsideActivity implements ListInterface, GroupedExportIn
private AsideActivityCategoryRepository $asideActivityCategoryRepository,
private CategoryRender $categoryRender,
private LocationRepository $locationRepository,
private TranslatableStringHelperInterface $translatableStringHelper
private TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function buildForm(FormBuilderInterface $builder) {}

View File

@@ -27,7 +27,7 @@ class ByActivityTypeFilter implements FilterInterface
public function __construct(
private readonly CategoryRender $categoryRender,
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly AsideActivityCategoryRepository $asideActivityTypeRepository
private readonly AsideActivityCategoryRepository $asideActivityTypeRepository,
) {}
public function addRole(): ?string

View File

@@ -24,7 +24,7 @@ use Symfony\Component\Security\Core\Security;
final readonly class ByLocationFilter implements FilterInterface
{
public function __construct(
private Security $security
private Security $security,
) {}
public function getTitle(): string

View File

@@ -29,7 +29,7 @@ class ByUserJobFilter implements FilterInterface
public function __construct(
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly UserJobRepositoryInterface $userJobRepository
private readonly UserJobRepositoryInterface $userJobRepository,
) {}
public function addRole(): ?string

View File

@@ -29,7 +29,7 @@ class ByUserScopeFilter implements FilterInterface
public function __construct(
private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -44,7 +44,7 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
CountNotificationTask $counter,
TokenStorageInterface $tokenStorage,
TranslatorInterface $translator,
AuthorizationCheckerInterface $authorizationChecker
AuthorizationCheckerInterface $authorizationChecker,
) {
$this->counter = $counter;
$this->tokenStorage = $tokenStorage;

View File

@@ -26,7 +26,7 @@ class AsideActivityVoter extends AbstractChillVoter implements ProvideRoleHierar
private readonly VoterHelperInterface $voterHelper;
public function __construct(
VoterHelperFactoryInterface $voterHelperFactory
VoterHelperFactoryInterface $voterHelperFactory,
) {
$this->voterHelper = $voterHelperFactory
->generate(self::class)

View File

@@ -47,7 +47,7 @@ class SendTestShortMessageOnCalendarCommand extends Command
private readonly PhoneNumberHelperInterface $phoneNumberHelper,
private readonly ShortMessageForCalendarBuilderInterface $messageForCalendarBuilder,
private readonly ShortMessageTransporterInterface $transporter,
private readonly UserRepositoryInterface $userRepository
private readonly UserRepositoryInterface $userRepository,
) {
parent::__construct('chill:calendar:test-send-short-message');
}

View File

@@ -59,7 +59,7 @@ class CalendarController extends AbstractController
private readonly AccompanyingPeriodRepository $accompanyingPeriodRepository,
private readonly UserRepositoryInterface $userRepository,
private readonly TranslatorInterface $translator,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
) {}
/**

View File

@@ -47,7 +47,7 @@ class CalendarDoc implements TrackCreationInterface, TrackUpdateInterface
Calendar $calendar,
#[ORM\ManyToOne(targetEntity: StoredObject::class, cascade: ['persist'])]
#[ORM\JoinColumn(nullable: false)]
private ?StoredObject $storedObject
private ?StoredObject $storedObject,
) {
$this->setCalendar($calendar);
$this->datetimeVersion = $calendar->getDateTimeVersion();

View File

@@ -26,7 +26,7 @@ final readonly class JobAggregator implements AggregatorInterface
public function __construct(
private UserJobRepository $jobRepository,
private TranslatableStringHelper $translatableStringHelper
private TranslatableStringHelper $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -26,7 +26,7 @@ final readonly class ScopeAggregator implements AggregatorInterface
public function __construct(
private ScopeRepository $scopeRepository,
private TranslatableStringHelper $translatableStringHelper
private TranslatableStringHelper $translatableStringHelper,
) {}
public function addRole(): ?string

View File

@@ -28,7 +28,7 @@ final readonly class JobFilter implements FilterInterface
public function __construct(
private TranslatableStringHelper $translatableStringHelper,
private UserJobRepositoryInterface $userJobRepository
private UserJobRepositoryInterface $userJobRepository,
) {}
public function addRole(): ?string

View File

@@ -30,7 +30,7 @@ class ScopeFilter implements FilterInterface
public function __construct(
protected TranslatorInterface $translator,
private readonly TranslatableStringHelper $translatableStringHelper,
private readonly ScopeRepositoryInterface $scopeRepository
private readonly ScopeRepositoryInterface $scopeRepository,
) {}
public function addRole(): ?string

View File

@@ -37,7 +37,7 @@ class CalendarType extends AbstractType
private readonly IdToUsersDataTransformer $idToUsersDataTransformer,
private readonly IdToLocationDataTransformer $idToLocationDataTransformer,
private readonly ThirdPartiesToIdDataTransformer $partiesToIdDataTransformer,
private readonly IdToCalendarRangeDataTransformer $calendarRangeDataTransformer
private readonly IdToCalendarRangeDataTransformer $calendarRangeDataTransformer,
) {}
public function buildForm(FormBuilderInterface $builder, array $options)

View File

@@ -46,7 +46,7 @@ class CalendarMessage
public function __construct(
Calendar $calendar,
private readonly string $action,
User $byUser
User $byUser,
) {
$this->calendarId = $calendar->getId();
$this->byUserId = $byUser->getId();

View File

@@ -59,7 +59,7 @@ final readonly class MSUserAbsenceReader implements MSUserAbsenceReaderInterface
'alwaysEnabled' => true,
'scheduled' => RemoteEventConverter::convertStringDateWithoutTimezone($automaticRepliesSettings['scheduledStartDateTime']['dateTime']) < $this->clock->now()
&& RemoteEventConverter::convertStringDateWithoutTimezone($automaticRepliesSettings['scheduledEndDateTime']['dateTime']) > $this->clock->now(),
default => throw new UserAbsenceSyncException('this status is not documented by Microsoft')
default => throw new UserAbsenceSyncException('this status is not documented by Microsoft'),
};
}
}

View File

@@ -177,7 +177,7 @@ class MapCalendarToUser
User $user,
int $expiration,
?string $id = null,
?string $secret = null
?string $secret = null,
): void {
$user->setAttributeByDomain(self::METADATA_KEY, self::EXPIRATION_SUBSCRIPTION_EVENT, $expiration);

View File

@@ -57,7 +57,7 @@ class RemoteEventConverter
private readonly LocationConverter $locationConverter,
private readonly LoggerInterface $logger,
private readonly PersonRenderInterface $personRender,
private readonly TranslatorInterface $translator
private readonly TranslatorInterface $translator,
) {
$this->defaultDateTimeZone = (new \DateTimeImmutable())->getTimezone();
$this->remoteDateTimeZone = self::getRemoteTimeZone();

View File

@@ -351,7 +351,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
[
'id' => $id,
'lastModifiedDateTime' => $lastModified,
'changeKey' => $changeKey
'changeKey' => $changeKey,
] = $this->createOnRemote($eventData, $calendar->getMainUser(), 'calendar_'.$calendar->getId());
if (null === $id) {
@@ -427,7 +427,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
[
'id' => $id,
'lastModifiedDateTime' => $lastModified,
'changeKey' => $changeKey
'changeKey' => $changeKey,
] = $this->createOnRemote(
$eventData,
$calendarRange->getUser(),
@@ -564,7 +564,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
[
'id' => $id,
'lastModifiedDateTime' => $lastModified,
'changeKey' => $changeKey
'changeKey' => $changeKey,
] = $this->patchOnRemote(
$calendar->getRemoteId(),
$eventData,

View File

@@ -33,6 +33,6 @@ class RemoteEvent
#[Serializer\Groups(['read'])]
public \DateTimeImmutable $endDate,
#[Serializer\Groups(['read'])]
public bool $isAllDay = false
public bool $isAllDay = false,
) {}
}

View File

@@ -65,7 +65,7 @@ class CalendarRangeRepository implements ObjectRepository
\DateTimeImmutable $from,
\DateTimeImmutable $to,
?int $limit = null,
?int $offset = null
?int $offset = null,
): array {
$qb = $this->buildQueryAvailableRangesForUser($user, $from, $to);

View File

@@ -1,7 +1,7 @@
<template>
<div class="row">
<div class="col-sm">
<label class="form-label">{{ $t('created_availabilities') }}</label>
<label class="form-label">{{ $t("created_availabilities") }}</label>
<vue-multiselect
v-model="pickedLocation"
:options="locations"
@@ -14,10 +14,15 @@
></vue-multiselect>
</div>
</div>
<div class="display-options row justify-content-between" style="margin-top: 1rem;">
<div
class="display-options row justify-content-between"
style="margin-top: 1rem"
>
<div class="col-sm-9 col-xs-12">
<div class="input-group mb-3">
<label class="input-group-text" for="slotDuration">Durée des créneaux</label>
<label class="input-group-text" for="slotDuration"
>Durée des créneaux</label
>
<select v-model="slotDuration" id="slotDuration" class="form-select">
<option value="00:05:00">5 minutes</option>
<option value="00:10:00">10 minutes</option>
@@ -58,13 +63,20 @@
</select>
</div>
</div>
<div class="col-sm-3 col-xs-12">
<div class="col-xs-12 col-sm-3">
<div class="float-end">
<div class="form-check input-group">
<span class="input-group-text">
<input id="showHideWE" class="mt-0" type="checkbox" v-model="showWeekends">
<input
id="showHideWE"
class="mt-0"
type="checkbox"
v-model="showWeekends"
/>
</span>
<label for="showHideWE" class="form-check-label input-group-text">Week-ends</label>
<label for="showHideWE" class="form-check-label input-group-text"
>Week-ends</label
>
</div>
</div>
</div>
@@ -72,39 +84,86 @@
<FullCalendar :options="calendarOptions" ref="calendarRef">
<template v-slot:eventContent="arg: EventApi">
<span :class="eventClasses(arg.event)">
<b v-if="arg.event.extendedProps.is === 'remote'">{{ arg.event.title}}</b>
<b v-else-if="arg.event.extendedProps.is === 'range'">{{ arg.timeText }} - {{ arg.event.extendedProps.locationName }}</b>
<b v-else-if="arg.event.extendedProps.is === 'local'">{{ arg.event.title}}</b>
<b v-else >no 'is'</b>
<a v-if="arg.event.extendedProps.is === 'range'" class="fa fa-fw fa-times delete"
@click.prevent="onClickDelete(arg.event)">
</a>
</span>
<b v-if="arg.event.extendedProps.is === 'remote'">{{
arg.event.title
}}</b>
<b v-else-if="arg.event.extendedProps.is === 'range'"
>{{ arg.timeText }} - {{ arg.event.extendedProps.locationName }}</b
>
<b v-else-if="arg.event.extendedProps.is === 'local'">{{
arg.event.title
}}</b>
<b v-else>no 'is'</b>
<a
v-if="arg.event.extendedProps.is === 'range'"
class="fa fa-fw fa-times delete"
@click.prevent="onClickDelete(arg.event)"
>
</a>
</span>
</template>
</FullCalendar>
<div id="copy-widget">
<div class="container">
<div class="row align-items-center">
<div class="col-sm-4 col-xs-12">
<h6 class="chill-red">{{ $t('copy_range_from_to') }}</h6>
</div>
<div class="col-sm-3 col-xs-12">
<input class="form-control" type="date" v-model="copyFrom" />
</div>
<div class="col-sm-1 col-xs-12" style="text-align: center; font-size: x-large;">
<i class="fa fa-angle-double-right"></i>
</div>
<div class="col-sm-3 col-xs-12" >
<input class="form-control" type="date" v-model="copyTo" />
</div>
<div class="col-sm-1">
<button class="btn btn-action" @click="copyDay">
{{ $t('copy_range') }}
</button>
<div class="container mt-2 mb-2">
<div class="row justify-content-between align-items-center mb-4">
<div class="col-xs-12 col-sm-3 col-md-2">
<h6 class="chill-red">{{ $t("copy_range_from_to") }}</h6>
</div>
<div class="col-xs-12 col-sm-9 col-md-2">
<select v-model="dayOrWeek" id="dayOrWeek" class="form-select">
<option value="day">{{ $t("from_day_to_day") }}</option>
<option value="week">{{ $t("from_week_to_week") }}</option>
</select>
</div>
<template v-if="dayOrWeek === 'day'">
<div class="col-xs-12 col-sm-3 col-md-3">
<input class="form-control" type="date" v-model="copyFrom" />
</div>
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
<i class="fa fa-angle-double-right"></i>
</div>
<div class="col-xs-12 col-sm-3 col-md-3">
<input class="form-control" type="date" v-model="copyTo" />
</div>
<div class="col-xs-12 col-sm-5 col-md-1">
<button class="btn btn-action float-end" @click="copyDay">
{{ $t("copy_range") }}
</button>
</div>
</template>
<template v-else>
<div class="col-xs-12 col-sm-3 col-md-3">
<select
v-model="copyFromWeek"
id="copyFromWeek"
class="form-select"
>
<option v-for="w in lastWeeks" :value="w.value" :key="w.value">
{{ w.text }}
</option>
</select>
</div>
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
<i class="fa fa-angle-double-right"></i>
</div>
<div class="col-xs-12 col-sm-3 col-md-3">
<select v-model="copyToWeek" id="copyToWeek" class="form-select">
<option v-for="w in nextWeeks" :value="w.value" :key="w.value">
{{ w.text }}
</option>
</select>
</div>
<div class="col-xs-12 col-sm-5 col-md-1">
<button class="btn btn-action float-end" @click="copyWeek">
{{ $t("copy_range") }}
</button>
</div>
</template>
</div>
</div>
</div>
</div>
<!-- not directly seen, but include in a modal -->
@@ -112,42 +171,95 @@
</template>
<script setup lang="ts">
import type {
CalendarOptions,
DatesSetArg,
EventInput
} from '@fullcalendar/core';
import {reactive, computed, ref} from "vue";
import {useStore} from "vuex";
import {key} from './store';
import FullCalendar from '@fullcalendar/vue3';
import frLocale from '@fullcalendar/core/locales/fr';
import interactionPlugin, {DropArg, EventResizeDoneArg} from "@fullcalendar/interaction";
EventInput,
} from "@fullcalendar/core";
import { reactive, computed, ref, onMounted } from "vue";
import { useStore } from "vuex";
import { key } from "./store";
import FullCalendar from "@fullcalendar/vue3";
import frLocale from "@fullcalendar/core/locales/fr";
import interactionPlugin, {
DropArg,
EventResizeDoneArg,
} from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid";
import {EventApi, DateSelectArg, EventDropArg, EventClickArg} from "@fullcalendar/core";
import {ISOToDate} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
import {
EventApi,
DateSelectArg,
EventDropArg,
EventClickArg,
} from "@fullcalendar/core";
import {
dateToISO,
ISOToDate,
} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
import VueMultiselect from "vue-multiselect";
import {Location} from "../../../../../ChillMainBundle/Resources/public/types";
import { Location } from "../../../../../ChillMainBundle/Resources/public/types";
import EditLocation from "./Components/EditLocation.vue";
import {useI18n} from "vue-i18n";
import { useI18n } from "vue-i18n";
const store = useStore(key);
const {t} = useI18n();
const { t } = useI18n();
const showWeekends = ref(false);
const slotDuration = ref('00:05:00');
const slotMinTime = ref('09:00:00');
const slotMaxTime = ref('18:00:00');
const slotDuration = ref("00:15:00");
const slotMinTime = ref("09:00:00");
const slotMaxTime = ref("18:00:00");
const copyFrom = ref<string | null>(null);
const copyTo = ref<string | null>(null);
const editLocation = ref<InstanceType<typeof EditLocation> | null>(null)
const editLocation = ref<InstanceType<typeof EditLocation> | null>(null);
const dayOrWeek = ref("day");
const copyFromWeek = ref<string | null>(null);
const copyToWeek = ref<string | null>(null);
interface Weeks {
value: string | null;
text: string;
}
const getMonday = (week: number): Date => {
const lastMonday = new Date();
lastMonday.setDate(
lastMonday.getDate() - ((lastMonday.getDay() + 6) % 7) + week * 7
);
return lastMonday;
};
const dateOptions: Intl.DateTimeFormatOptions = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
const lastWeeks = computed((): Weeks[] =>
Array.from(Array(30).keys()).map((w) => {
const lastMonday = getMonday(15-w);
return {
value: dateToISO(lastMonday),
text: `Semaine du ${lastMonday.toLocaleDateString("fr-FR", dateOptions)}`,
};
})
);
const nextWeeks = computed((): Weeks[] =>
Array.from(Array(52).keys()).map((w) => {
const nextMonday = getMonday(w + 1);
return {
value: dateToISO(nextMonday),
text: `Semaine du ${nextMonday.toLocaleDateString("fr-FR", dateOptions)}`,
};
})
);
const baseOptions = ref<CalendarOptions>({
locale: frLocale,
plugins: [interactionPlugin, timeGridPlugin],
initialView: 'timeGridWeek',
initialView: "timeGridWeek",
initialDate: new Date(),
scrollTimeReset: false,
selectable: true,
@@ -164,9 +276,9 @@ const baseOptions = ref<CalendarOptions>({
selectMirror: false,
editable: true,
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'timeGridWeek,timeGridDay'
left: "prev,next today",
center: "title",
right: "timeGridWeek,timeGridDay",
},
});
@@ -180,20 +292,23 @@ const locations = computed<Location[]>(() => {
const pickedLocation = computed<Location | null>({
get(): Location | null {
return store.state.locations.locationPicked || store.state.locations.currentLocation;
return (
store.state.locations.locationPicked ||
store.state.locations.currentLocation
);
},
set(newLocation: Location | null): void {
store.commit('locations/setLocationPicked', newLocation, {root: true});
}
})
store.commit("locations/setLocationPicked", newLocation, { root: true });
},
});
/**
* return the show classes for the event
* @param arg
*/
const eventClasses = function(arg: EventApi): object {
return {'calendarRangeItems': true};
}
const eventClasses = function (arg: EventApi): object {
return { calendarRangeItems: true };
};
/*
// currently, all events are stored into calendarRanges, due to reactivity bug
@@ -230,51 +345,60 @@ const calendarOptions = computed((): CalendarOptions => {
* launched when the calendar range date change
*/
function onDatesSet(event: DatesSetArg): void {
store.dispatch('fullCalendar/setCurrentDatesView', {start: event.start, end: event.end});
store.dispatch("fullCalendar/setCurrentDatesView", {
start: event.start,
end: event.end,
});
}
function onDateSelect(event: DateSelectArg): void {
if (null === pickedLocation.value) {
window.alert("Indiquez une localisation avant de créer une période de disponibilité.");
window.alert(
"Indiquez une localisation avant de créer une période de disponibilité."
);
return;
}
store.dispatch('calendarRanges/createRange', {start: event.start, end: event.end, location: pickedLocation.value});
store.dispatch("calendarRanges/createRange", {
start: event.start,
end: event.end,
location: pickedLocation.value,
});
}
/**
* When a calendar range is deleted
*/
function onClickDelete(event: EventApi): void {
console.log('onClickDelete', event);
if (event.extendedProps.is !== 'range') {
if (event.extendedProps.is !== "range") {
return;
}
store.dispatch('calendarRanges/deleteRange', event.extendedProps.calendarRangeId);
store.dispatch(
"calendarRanges/deleteRange",
event.extendedProps.calendarRangeId
);
}
function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
if (payload.event.extendedProps.is !== 'range') {
if (payload.event.extendedProps.is !== "range") {
return;
}
const changedEvent = payload.event;
store.dispatch('calendarRanges/patchRangeTime', {
store.dispatch("calendarRanges/patchRangeTime", {
calendarRangeId: payload.event.extendedProps.calendarRangeId,
start: payload.event.start,
end: payload.event.end,
});
};
}
function onEventClick(payload: EventClickArg): void {
// @ts-ignore TS does not recognize the target. But it does exists.
if (payload.jsEvent.target.classList.contains('delete')) {
if (payload.jsEvent.target.classList.contains("delete")) {
return;
}
if (payload.event.extendedProps.is !== 'range') {
if (payload.event.extendedProps.is !== "range") {
return;
}
@@ -285,10 +409,26 @@ function copyDay() {
if (null === copyFrom.value || null === copyTo.value) {
return;
}
store.dispatch('calendarRanges/copyFromDayToAnotherDay', {from: ISOToDate(copyFrom.value), to: ISOToDate(copyTo.value)})
store.dispatch("calendarRanges/copyFromDayToAnotherDay", {
from: ISOToDate(copyFrom.value),
to: ISOToDate(copyTo.value),
});
}
function copyWeek() {
if (null === copyFromWeek.value || null === copyToWeek.value) {
return;
}
store.dispatch("calendarRanges/copyFromWeekToAnotherWeek", {
fromMonday: ISOToDate(copyFromWeek.value),
toMonday: ISOToDate(copyToWeek.value),
});
}
onMounted(() => {
copyFromWeek.value = dateToISO(getMonday(0));
copyToWeek.value = dateToISO(getMonday(1));
});
</script>
<style scoped>
@@ -299,4 +439,9 @@ function copyDay() {
z-index: 9999999999;
padding: 0.25rem 0 0.25rem;
}
div.copy-chevron {
text-align: center;
font-size: x-large;
width: 2rem;
}
</style>

View File

@@ -5,11 +5,9 @@ const appMessages = {
show_my_calendar: "Afficher mon calendrier",
show_weekends: "Afficher les week-ends",
copy_range: "Copier",
copy_range_from_to: "Copier les plages d'un jour à l'autre",
copy_range_to_next_day: "Copier les plages du jour au jour suivant",
copy_range_from_day: "Copier les plages du ",
to_the_next_day: " au jour suivant",
copy_range_to_next_week: "Copier les plages de la semaine à la semaine suivante",
copy_range_from_to: "Copier les plages",
from_day_to_day: "d'un jour à l'autre",
from_week_to_week: "d'une semaine à l'autre",
copy_range_how_to: "Créez les plages de disponibilités durant une journée et copiez-les facilement au jour suivant avec ce bouton. Si les week-ends sont cachés, le jour suivant un vendredi sera le lundi.",
new_range_to_save: "Nouvelles plages à enregistrer",
update_range_to_save: "Plages à modifier",

View File

@@ -52,6 +52,23 @@ export default <Module<CalendarRangesState, State>>{
}
}
return founds;
},
getRangesOnWeek: (state: CalendarRangesState) => (mondayDate: Date): EventInputCalendarRange[] => {
const founds = [];
for (let d of Array.from(Array(7).keys())) {
const dateOfWeek = new Date(mondayDate);
dateOfWeek.setDate(mondayDate.getDate() + d);
const dateStr = <string>dateToISO(dateOfWeek);
for (let range of state.ranges) {
if (isEventInputCalendarRange(range)
&& range.start.startsWith(dateStr)
) {
founds.push(range);
}
}
}
return founds;
},
},
@@ -238,7 +255,7 @@ export default <Module<CalendarRangesState, State>>{
for (let r of rangesToCopy) {
let start = new Date(<Date>ISOToDatetime(r.start));
start.setFullYear(to.getFullYear(), to.getMonth(), to.getDate())
start.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
let end = new Date(<Date>ISOToDatetime(r.end));
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
let location = ctx.rootGetters['locations/getLocationById'](r.locationId);
@@ -246,6 +263,23 @@ export default <Module<CalendarRangesState, State>>{
promises.push(ctx.dispatch('createRange', {start, end, location}));
}
return Promise.all(promises).then(_ => Promise.resolve(null));
},
copyFromWeekToAnotherWeek(ctx, {fromMonday, toMonday}: {fromMonday: Date, toMonday: Date}): Promise<null> {
const rangesToCopy: EventInputCalendarRange[] = ctx.getters['getRangesOnWeek'](fromMonday);
const promises = [];
const diffTime = toMonday.getTime() - fromMonday.getTime();
for (let r of rangesToCopy) {
let start = new Date(<Date>ISOToDatetime(r.start));
let end = new Date(<Date>ISOToDatetime(r.end));
start.setTime(start.getTime() + diffTime);
end.setTime(end.getTime() + diffTime);
let location = ctx.rootGetters['locations/getLocationById'](r.locationId);
promises.push(ctx.dispatch('createRange', {start, end, location}));
}
return Promise.all(promises).then(_ => Promise.resolve(null));
}
}

View File

@@ -40,7 +40,7 @@ final readonly class CalendarContext implements CalendarContextInterface
private PersonRepository $personRepository,
private ThirdPartyRender $thirdPartyRender,
private ThirdPartyRepository $thirdPartyRepository,
private TranslatableStringHelperInterface $translatableStringHelper
private TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function adminFormReverseTransform(array $data): array

View File

@@ -37,7 +37,7 @@ final readonly class AccompanyingPeriodCalendarGenericDocProvider implements Gen
public function __construct(
private Security $security,
private EntityManagerInterface $em
private EntityManagerInterface $em,
) {}
/**

View File

@@ -36,7 +36,7 @@ final readonly class PersonCalendarGenericDocProvider implements GenericDocForPe
public function __construct(
private Security $security,
private EntityManagerInterface $em
private EntityManagerInterface $em,
) {}
private function addWhereClausesToQuery(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery

View File

@@ -156,7 +156,7 @@ final class CalendarTypeTest extends TypeTestCase
private function buildMultiToIdDataTransformer(
string $classTransformer,
string $objClass
string $objClass,
) {
$transformer = $this->prophesize($classTransformer);
$transformer->transform(Argument::type('array'))
@@ -195,7 +195,7 @@ final class CalendarTypeTest extends TypeTestCase
private function buildSingleToIdDataTransformer(
string $classTransformer,
string $class
string $class,
) {
$transformer = $this->prophesize($classTransformer);
$transformer->transform(Argument::type('object'))

View File

@@ -203,7 +203,7 @@ final class CalendarContextTest extends TestCase
private function buildCalendarContext(
?EntityManagerInterface $entityManager = null,
?NormalizerInterface $normalizer = null
?NormalizerInterface $normalizer = null,
): CalendarContext {
$baseContext = $this->prophesize(BaseContextData::class);
$baseContext->getData(null)->willReturn(['base_context' => 'data']);

View File

@@ -44,7 +44,7 @@ class CreateFieldsOnGroupCommand extends Command
private readonly EntityManager $entityManager,
private readonly ValidatorInterface $validator,
private $availableLanguages,
private $customizablesEntities
private $customizablesEntities,
) {
parent::__construct();
}

View File

@@ -39,7 +39,7 @@ class CustomFieldsGroupController extends AbstractController
public function __construct(
private readonly CustomFieldProvider $customFieldProvider,
private readonly TranslatorInterface $translator,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
) {}
/**

View File

@@ -42,7 +42,7 @@ class CustomFieldChoice extends AbstractCustomField
/**
* @var TranslatableStringHelper Helper that find the string in current locale from an array of translation
*/
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
public function allowOtherChoice(CustomField $cf)

View File

@@ -44,7 +44,7 @@ class CustomFieldDate extends AbstractCustomField
public function __construct(
private readonly Environment $templating,
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
public function buildForm(FormBuilderInterface $builder, CustomField $customField)

View File

@@ -41,7 +41,7 @@ class CustomFieldNumber extends AbstractCustomField
public function __construct(
private readonly Environment $templating,
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
public function buildForm(FormBuilderInterface $builder, CustomField $customField)

View File

@@ -28,7 +28,7 @@ class CustomFieldText extends AbstractCustomField
public function __construct(
private readonly Environment $templating,
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
/**

View File

@@ -31,7 +31,7 @@ class CustomFieldTitle extends AbstractCustomField
/**
* @var TranslatableStringHelper Helper that find the string in current locale from an array of translation
*/
private readonly TranslatableStringHelper $translatableStringHelper
private readonly TranslatableStringHelper $translatableStringHelper,
) {}
public function buildForm(FormBuilderInterface $builder, CustomField $customField)

View File

@@ -26,7 +26,7 @@ class CustomFieldsGroupType extends AbstractType
public function __construct(
private readonly array $customizableEntities,
// TODO : add comment about this variable
private readonly TranslatorInterface $translator
private readonly TranslatorInterface $translator,
) {}
// TODO : details about the function

View File

@@ -48,7 +48,7 @@ final class DocGeneratorTemplateController extends AbstractController
private readonly PaginatorFactory $paginatorFactory,
private readonly EntityManagerInterface $entityManager,
private readonly ClockInterface $clock,
private readonly ChillSecurity $security
private readonly ChillSecurity $security,
) {}
#[Route(path: '{_locale}/admin/doc/gen/generate/test/from/{template}/for/{entityClassName}/{entityId}', name: 'chill_docgenerator_test_generate_from_template')]
@@ -56,7 +56,7 @@ final class DocGeneratorTemplateController extends AbstractController
DocGeneratorTemplate $template,
string $entityClassName,
int $entityId,
Request $request
Request $request,
): Response {
return $this->generateDocFromTemplate(
$template,
@@ -71,7 +71,7 @@ final class DocGeneratorTemplateController extends AbstractController
DocGeneratorTemplate $template,
string $entityClassName,
int $entityId,
Request $request
Request $request,
): Response {
return $this->generateDocFromTemplate(
$template,
@@ -137,7 +137,7 @@ final class DocGeneratorTemplateController extends AbstractController
DocGeneratorTemplate $template,
int $entityId,
Request $request,
bool $isTest
bool $isTest,
): Response {
try {
$context = $this->contextManager->getContextByDocGeneratorTemplate($template);

View File

@@ -54,12 +54,15 @@ class LoadDocGeneratorTemplate extends AbstractFixture
];
foreach ($templates as $template) {
$newStoredObj = (new StoredObject())
->setFilename($template['file']['filename'])
->setKeyInfos(json_decode($template['file']['key'], true))
->setIv(json_decode($template['file']['iv'], true))
$newStoredObj = (new StoredObject());
$newStoredObj
->setCreatedAt(new \DateTime('today'))
->setType($template['file']['type']);
->registerVersion(
json_decode($template['file']['key'], true),
json_decode($template['file']['iv'], true),
$template['file']['type'],
);
$manager->persist($newStoredObj);

View File

@@ -28,7 +28,7 @@ final readonly class RelatorioDriver implements DriverInterface
public function __construct(
private HttpClientInterface $client,
ParameterBagInterface $parameterBag,
private LoggerInterface $logger
private LoggerInterface $logger,
) {
$this->url = $parameterBag->get('chill_doc_generator')['driver']['relatorio']['url'];
}

View File

@@ -35,7 +35,7 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte
public function __construct(
private readonly ClassMetadataFactoryInterface $classMetadataFactory,
private readonly TranslatableStringHelperInterface $translatableStringHelper
private readonly TranslatableStringHelperInterface $translatableStringHelper,
) {
$this->propertyAccess = PropertyAccess::createPropertyAccessor();
}

View File

@@ -33,7 +33,7 @@ class Generator implements GeneratorInterface
private readonly DriverInterface $driver,
private readonly ManagerRegistry $objectManagerRegistry,
private readonly LoggerInterface $logger,
private readonly StoredObjectManagerInterface $storedObjectManager
private readonly StoredObjectManagerInterface $storedObjectManager,
) {}
public function generateDataDump(
@@ -134,13 +134,11 @@ class Generator implements GeneratorInterface
$content = Yaml::dump($data, 6);
/* @var StoredObject $destinationStoredObject */
$destinationStoredObject
->setType('application/yaml')
->setFilename(sprintf('%s_yaml', uniqid('doc_', true)))
->setStatus(StoredObject::STATUS_READY)
;
try {
$this->storedObjectManager->write($destinationStoredObject, $content);
$this->storedObjectManager->write($destinationStoredObject, $content, 'application/yaml');
} catch (StoredObjectManagerException $e) {
$destinationStoredObject->addGenerationErrors($e->getMessage());
@@ -174,13 +172,11 @@ class Generator implements GeneratorInterface
/* @var StoredObject $destinationStoredObject */
$destinationStoredObject
->setType($template->getFile()->getType())
->setFilename(sprintf('%s_odt', uniqid('doc_', true)))
->setStatus(StoredObject::STATUS_READY)
;
try {
$this->storedObjectManager->write($destinationStoredObject, $generatedResource);
$this->storedObjectManager->write($destinationStoredObject, $generatedResource, $template->getFile()->getType());
} catch (StoredObjectManagerException $e) {
$destinationStoredObject->addGenerationErrors($e->getMessage());

View File

@@ -39,7 +39,7 @@ final readonly class OnGenerationFails implements EventSubscriberInterface
private MailerInterface $mailer,
private StoredObjectRepositoryInterface $storedObjectRepository,
private TranslatorInterface $translator,
private UserRepositoryInterface $userRepository
private UserRepositoryInterface $userRepository,
) {}
public static function getSubscribedEvents()

View File

@@ -56,7 +56,7 @@ final class BaseContextDataTest extends KernelTestCase
}
private function buildBaseContext(
?NormalizerInterface $normalizer = null
?NormalizerInterface $normalizer = null,
): BaseContextData {
return new BaseContextData(
$normalizer ?? self::getContainer()->get(NormalizerInterface::class)

View File

@@ -19,6 +19,7 @@ use Chill\DocGeneratorBundle\Service\Generator\Generator;
use Chill\DocGeneratorBundle\Service\Generator\ObjectReadyException;
use Chill\DocGeneratorBundle\Service\Generator\RelatedEntityNotFoundException;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Entity\StoredObjectVersion;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
@@ -39,11 +40,11 @@ class GeneratorTest extends TestCase
public function testSuccessfulGeneration(): void
{
$template = (new DocGeneratorTemplate())->setFile($templateStoredObject = (new StoredObject())
->setType('application/test'));
$templateStoredObject = new StoredObject();
$templateStoredObject->registerVersion(type: 'application/test');
$template = (new DocGeneratorTemplate())->setFile($templateStoredObject);
$destinationStoredObject = (new StoredObject())->setStatus(StoredObject::STATUS_PENDING);
$reflection = new \ReflectionClass($destinationStoredObject);
$reflection->getProperty('id')->setAccessible(true);
$reflection->getProperty('id')->setValue($destinationStoredObject, 1);
$entity = new class () {};
$data = [];
@@ -76,7 +77,14 @@ class GeneratorTest extends TestCase
$storedObjectManager = $this->prophesize(StoredObjectManagerInterface::class);
$storedObjectManager->read($templateStoredObject)->willReturn('template');
$storedObjectManager->write($destinationStoredObject, 'generated')->shouldBeCalled();
$storedObjectManager->write($destinationStoredObject, 'generated', 'application/test')
->will(function ($args): StoredObjectVersion {
/** @var StoredObject $storedObject */
$storedObject = $args[0];
return $storedObject->registerVersion(type: $args[2]);
})
->shouldBeCalled();
$generator = new Generator(
$contextManagerInterface->reveal(),
@@ -107,8 +115,9 @@ class GeneratorTest extends TestCase
$this->prophesize(StoredObjectManagerInterface::class)->reveal()
);
$template = (new DocGeneratorTemplate())->setFile($templateStoredObject = (new StoredObject())
->setType('application/test'));
$templateStoredObject = new StoredObject();
$templateStoredObject->registerVersion(type: 'application/test');
$template = (new DocGeneratorTemplate())->setFile($templateStoredObject);
$destinationStoredObject = (new StoredObject())->setStatus(StoredObject::STATUS_READY);
$generator->generateDocFromTemplate(
@@ -124,11 +133,11 @@ class GeneratorTest extends TestCase
{
$this->expectException(RelatedEntityNotFoundException::class);
$template = (new DocGeneratorTemplate())->setFile($templateStoredObject = (new StoredObject())
->setType('application/test'));
$templateStoredObject = new StoredObject();
$templateStoredObject->registerVersion(type: 'application/test');
$template = (new DocGeneratorTemplate())->setFile($templateStoredObject);
$destinationStoredObject = (new StoredObject())->setStatus(StoredObject::STATUS_PENDING);
$reflection = new \ReflectionClass($destinationStoredObject);
$reflection->getProperty('id')->setAccessible(true);
$reflection->getProperty('id')->setValue($destinationStoredObject, 1);
$context = $this->prophesize(DocGeneratorContextInterface::class);

View File

@@ -58,6 +58,7 @@ final readonly class TempUrlOpenstackGenerator implements TempUrlGeneratorInterf
?int $expire_delay = null,
?int $submit_delay = null,
int $max_file_count = 1,
?string $object_name = null,
): SignedUrlPost {
$delay = $expire_delay ?? $this->max_expire_delay;
$submit_delay ??= $this->max_submit_delay;
@@ -84,7 +85,9 @@ final readonly class TempUrlOpenstackGenerator implements TempUrlGeneratorInterf
$expires = $this->clock->now()->add(new \DateInterval('PT'.(string) $delay.'S'));
$object_name = $this->generateObjectName();
if (null === $object_name) {
$object_name = $this->generateObjectName();
}
$g = new SignedUrlPost(
$url = $this->generateUrl($object_name),
@@ -141,7 +144,7 @@ final readonly class TempUrlOpenstackGenerator implements TempUrlGeneratorInterf
{
return match (str_ends_with($this->base_url, '/')) {
true => $this->base_url.$relative_path,
false => $this->base_url.'/'.$relative_path
false => $this->base_url.'/'.$relative_path,
};
}
@@ -179,21 +182,19 @@ final readonly class TempUrlOpenstackGenerator implements TempUrlGeneratorInterf
return \hash_hmac('sha512', $body, $this->key, false);
}
private function generateSignature($method, $url, \DateTimeImmutable $expires)
private function generateSignature(string $method, $url, \DateTimeImmutable $expires)
{
if ('POST' === $method) {
return $this->generateSignaturePost($url, $expires);
}
$path = \parse_url((string) $url, PHP_URL_PATH);
$body = sprintf(
"%s\n%s\n%s",
$method,
strtoupper($method),
$expires->format('U'),
$path
)
;
);
$this->logger->debug(
'generate signature GET',

View File

@@ -16,7 +16,8 @@ interface TempUrlGeneratorInterface
public function generatePost(
?int $expire_delay = null,
?int $submit_delay = null,
int $max_file_count = 1
int $max_file_count = 1,
?string $object_name = null,
): SignedUrlPost;
public function generate(string $method, string $object_name, ?int $expire_delay = null): SignedUrl;

View File

@@ -25,7 +25,7 @@ class AsyncUploadExtension extends AbstractExtension
{
public function __construct(
private readonly TempUrlGeneratorInterface $tempUrlGenerator,
private readonly UrlGeneratorInterface $routingUrlGenerator
private readonly UrlGeneratorInterface $routingUrlGenerator,
) {}
public function getFilters()

View File

@@ -11,9 +11,11 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\AsyncUpload\Exception\TempUrlGeneratorException;
use Chill\DocStoreBundle\AsyncUpload\TempUrlGeneratorInterface;
use Chill\DocStoreBundle\Security\Authorization\AsyncUploadVoter;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Entity\StoredObjectVersion;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\MainBundle\Entity\User;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -30,62 +32,84 @@ final readonly class AsyncUploadController
private TempUrlGeneratorInterface $tempUrlGenerator,
private SerializerInterface $serializer,
private Security $security,
private LoggerInterface $logger,
private LoggerInterface $chillLogger,
) {}
#[Route(path: '/asyncupload/temp_url/generate/{method}', name: 'async_upload.generate_url')]
public function getSignedUrl(string $method, Request $request): JsonResponse
#[Route(path: '/api/1.0/doc-store/async-upload/temp_url/{uuid}/generate/post', name: 'chill_docstore_asyncupload_getsignedurlpost')]
public function getSignedUrlPost(Request $request, StoredObject $storedObject): JsonResponse
{
try {
switch (strtolower($method)) {
case 'post':
$p = $this->tempUrlGenerator
->generatePost(
$request->query->has('expires_delay') ? $request->query->getInt('expires_delay') : null,
$request->query->has('submit_delay') ? $request->query->getInt('submit_delay') : null
)
;
break;
case 'get':
case 'head':
$object_name = $request->query->get('object_name', null);
if (!$this->security->isGranted(StoredObjectRoleEnum::EDIT->value, $storedObject)) {
throw new AccessDeniedHttpException('not able to edit the given stored object');
}
if (null === $object_name) {
return (new JsonResponse((object) [
'message' => 'the object_name is null',
]))
->setStatusCode(JsonResponse::HTTP_BAD_REQUEST);
}
$p = $this->tempUrlGenerator->generate(
$method,
$object_name,
$request->query->has('expires_delay') ? $request->query->getInt('expires_delay') : null
);
break;
default:
return (new JsonResponse((object) ['message' => 'the method '
."{$method} is not valid"]))
->setStatusCode(JsonResponse::HTTP_BAD_REQUEST);
// we create a dummy version, to generate a filename
$version = $storedObject->registerVersion();
$p = $this->tempUrlGenerator
->generatePost(
$request->query->has('expires_delay') ? $request->query->getInt('expires_delay') : null,
$request->query->has('submit_delay') ? $request->query->getInt('submit_delay') : null,
object_name: $version->getFilename()
);
$this->chillLogger->notice('[Privacy Event] a request to upload a document has been generated', [
'doc_uuid' => $storedObject->getUuid(),
]);
return new JsonResponse(
$this->serializer->serialize($p, 'json', [AbstractNormalizer::GROUPS => ['read']]),
Response::HTTP_OK,
[],
true
);
}
#[Route(path: '/api/1.0/doc-store/async-upload/temp_url/{uuid}/generate/{method}', name: 'chill_docstore_asyncupload_getsignedurlget', requirements: ['method' => 'get|head'])]
public function getSignedUrlGet(Request $request, StoredObject $storedObject, string $method): JsonResponse
{
if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) {
throw new AccessDeniedHttpException('not able to read the given stored object');
}
// we really want to be sure that there are no other method than get or head:
if (!in_array($method, ['get', 'head'], true)) {
throw new AccessDeniedHttpException('Only methods get and head are allowed');
}
if ($request->query->has('version')) {
$filename = $request->query->get('version');
$storedObjectVersion = $storedObject->getVersions()->findFirst(fn (int $index, StoredObjectVersion $version): bool => $version->getFilename() === $filename);
if (null === $storedObjectVersion) {
// we are here in the case where the version is not stored into the database
// as the version is prefixed by the stored object prefix, we just have to check that this prefix
// is the same. It means that the user had previously the permission to "SEE_AND_EDIT" this stored
// object with same prefix that we checked before
if (!str_starts_with($filename, $storedObject->getPrefix())) {
throw new AccessDeniedHttpException('not able to match the version with the same filename');
}
}
} catch (TempUrlGeneratorException $e) {
$this->logger->warning('The client requested a temp url'
.' which sparkle an error.', [
'message' => $e->getMessage(),
'expire_delay' => $request->query->getInt('expire_delay', 0),
'file_count' => $request->query->getInt('file_count', 1),
'method' => $method,
]);
$p = new \stdClass();
$p->message = $e->getMessage();
$p->status = JsonResponse::HTTP_BAD_REQUEST;
return new JsonResponse($p, JsonResponse::HTTP_BAD_REQUEST);
} else {
$filename = $storedObject->getCurrentVersion()->getFilename();
}
if (!$this->security->isGranted(AsyncUploadVoter::GENERATE_SIGNATURE, $p)) {
throw new AccessDeniedHttpException('not allowed to generate this signature');
}
$p = $this->tempUrlGenerator->generate(
$method,
$filename,
$request->query->has('expires_delay') ? $request->query->getInt('expires_delay') : null
);
$user = $this->security->getUser();
$userId = match ($user instanceof User) {
true => $user->getId(),
false => $user->getUserIdentifier(),
};
$this->chillLogger->notice('[Privacy Event] a request to see a document has been granted', [
'doc_uuid' => $storedObject->getUuid()->toString(),
'user_id' => $userId,
]);
return new JsonResponse(
$this->serializer->serialize($p, 'json', [AbstractNormalizer::GROUPS => ['read']]),

View File

@@ -35,7 +35,7 @@ class DocumentAccompanyingCourseController extends AbstractController
protected TranslatorInterface $translator,
protected EventDispatcherInterface $eventDispatcher,
protected AuthorizationHelper $authorizationHelper,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
) {}
#[Route(path: '/{id}/delete', name: 'chill_docstore_accompanying_course_document_delete')]

View File

@@ -0,0 +1,55 @@
<?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\Controller;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\DocStoreBundle\Workflow\AccompanyingCourseDocumentDuplicator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
final readonly class DocumentAccompanyingCourseDuplicateController
{
public function __construct(
private Security $security,
private AccompanyingCourseDocumentDuplicator $documentWorkflowDuplicator,
private EntityManagerInterface $entityManager,
private UrlGeneratorInterface $urlGenerator,
) {}
#[Route('/{_locale}/doc-store/accompanying-course-document/{id}/duplicate', name: 'chill_doc_store_accompanying_course_document_duplicate')]
public function __invoke(AccompanyingCourseDocument $document, Request $request, Session $session): Response
{
if (!$this->security->isGranted(AccompanyingCourseDocumentVoter::SEE, $document)) {
throw new AccessDeniedHttpException('not allowed to see this document');
}
if (!$this->security->isGranted(AccompanyingCourseDocumentVoter::CREATE, $document->getCourse())) {
throw new AccessDeniedHttpException('not allowed to create this document');
}
$duplicated = $this->documentWorkflowDuplicator->duplicate($document);
$this->entityManager->persist($duplicated);
$this->entityManager->flush();
return new RedirectResponse(
$this->urlGenerator->generate('accompanying_course_document_edit', ['id' => $duplicated->getId(), 'course' => $duplicated->getCourse()->getId()])
);
}
}

View File

@@ -44,7 +44,7 @@ class DocumentPersonController extends AbstractController
protected AuthorizationHelper $authorizationHelper,
protected PDFSignatureZoneParser $PDFSignatureZoneParser,
protected StoredObjectManagerInterface $storedObjectManagerInterface,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
) {}
#[Route(path: '/{id}/delete', name: 'chill_docstore_person_document_delete')]
@@ -201,36 +201,4 @@ class DocumentPersonController extends AbstractController
['document' => $document, 'person' => $person]
);
}
#[Route(path: '/{id}/signature', name: 'person_document_signature', methods: 'GET')]
public function signature(Person $person, PersonDocument $document): Response
{
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_SEE', $document);
$event = new PrivacyEvent($person, [
'element_class' => PersonDocument::class,
'element_id' => $document->getId(),
'action' => 'show',
]);
$this->eventDispatcher->dispatch($event, PrivacyEvent::PERSON_PRIVACY_EVENT);
$storedObject = $document->getObject();
$content = $this->storedObjectManagerInterface->read($storedObject);
$zones = $this->PDFSignatureZoneParser->findSignatureZones($content);
$signature = [];
$signature['id'] = 1;
$signature['storedObject'] = [ // TEMP
'filename' => $storedObject->getFilename(),
'iv' => $storedObject->getIv(),
'keyInfos' => $storedObject->getKeyInfos(),
];
$signature['zones'] = $zones;
return $this->render(
'@ChillDocStore/PersonDocument/signature.html.twig',
['document' => $document, 'person' => $person, 'signature' => $signature]
);
}
}

View File

@@ -15,12 +15,19 @@ use Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner\RequestPdfSignMessa
use Chill\DocStoreBundle\Service\Signature\PDFPage;
use Chill\DocStoreBundle\Service\Signature\PDFSignatureZone;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepSignature;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderManagerInterface;
use Chill\MainBundle\Security\Authorization\EntityWorkflowStepSignatureVoter;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class SignatureRequestController
{
@@ -28,12 +35,24 @@ class SignatureRequestController
private readonly MessageBusInterface $messageBus,
private readonly StoredObjectManagerInterface $storedObjectManager,
private readonly EntityWorkflowManager $entityWorkflowManager,
private readonly ChillEntityRenderManagerInterface $entityRender,
private readonly NormalizerInterface $normalizer,
private readonly Security $security,
) {}
#[Route('/api/1.0/document/workflow/{id}/signature-request', name: 'chill_docstore_signature_request')]
public function processSignature(EntityWorkflowStepSignature $signature, Request $request): JsonResponse
{
if (!$this->security->isGranted(EntityWorkflowStepSignatureVoter::SIGN, $signature)) {
throw new AccessDeniedHttpException('not authorized to sign this step');
}
$entityWorkflow = $signature->getStep()->getEntityWorkflow();
if (EntityWorkflowSignatureStateEnum::PENDING !== $signature->getState()) {
return new JsonResponse([], status: Response::HTTP_CONFLICT);
}
$storedObject = $this->entityWorkflowManager->getAssociatedStoredObject($entityWorkflow);
$content = $this->storedObjectManager->read($storedObject);
@@ -51,8 +70,14 @@ class SignatureRequestController
$signature->getId(),
$zone,
$data['zone']['index'],
'test signature', // reason (string)
'Mme Caroline Diallo', // signerText (string)
'Signed by IP: '.(string) $request->getClientIp().', authenticated user: '.$this->entityRender->renderString($this->security->getUser(), []),
$this->entityRender->renderString($signature->getSigner(), [
// options for user render
'absence' => false,
'main_scope' => false,
// options for person render
'addAge' => false,
]),
$content
));
@@ -62,6 +87,16 @@ class SignatureRequestController
#[Route('/api/1.0/document/workflow/{id}/check-signature', name: 'chill_docstore_check_signature')]
public function checkSignature(EntityWorkflowStepSignature $signature): JsonResponse
{
return new JsonResponse($signature->getState(), JsonResponse::HTTP_OK, []);
$entityWorkflow = $signature->getStep()->getEntityWorkflow();
$storedObject = $this->entityWorkflowManager->getAssociatedStoredObject($entityWorkflow);
return new JsonResponse(
[
'state' => $signature->getState(),
'storedObject' => $this->normalizer->normalize($storedObject, 'json'),
],
JsonResponse::HTTP_OK,
[]
);
}
}

View File

@@ -11,6 +11,46 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
class StoredObjectApiController extends ApiController {}
class StoredObjectApiController extends ApiController
{
public function __construct(
private readonly Security $security,
private readonly SerializerInterface $serializer,
private readonly EntityManagerInterface $entityManager,
) {}
/**
* Creates a new stored object.
*
* @return JsonResponse the response containing the serialized object in JSON format
*
* @throws AccessDeniedHttpException if the user does not have the necessary role to create a stored object
*/
#[Route('/api/1.0/doc-store/stored-object/create', methods: ['POST'])]
public function createStoredObject(): JsonResponse
{
if (!($this->security->isGranted('ROLE_ADMIN') || $this->security->isGranted('ROLE_USER'))) {
throw new AccessDeniedHttpException('Must be user or admin to create a stored object');
}
$object = new StoredObject();
$this->entityManager->persist($object);
$this->entityManager->flush();
return new JsonResponse(
$this->serializer->serialize($object, 'json', [AbstractNormalizer::GROUPS => ['read']]),
json: true
);
}
}

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