mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 09:18:24 +00:00 
			
		
		
		
	Compare commits
	
		
			175 Commits
		
	
	
		
			2.15.2
			...
			testing-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 24eb13f440 | |||
| 2b14c132d5 | |||
| ae6355e1e7 | |||
| e96c246ef9 | |||
| d0af191a00 | |||
| 95ee573dc5 | |||
| 1004e98acd | |||
| 4ed50979bd | |||
| f1fa4d415e | |||
| 2312a8d46f | |||
| 67c3de733f | |||
| c05451bfe9 | |||
| 8be9fb6553 | |||
| f5f6eb78a2 | |||
| 7a7e66146b | |||
| 4bbad4fc61 | |||
| 86613a9be9 | |||
| 21bd6478ad | |||
| 5849d8d670 | |||
| 568ee079b5 | |||
| bf97b2a50c | |||
| 01785ed494 | |||
| 97d401b7f6 | |||
| 44ccfe92b6 | |||
| b6ea857389 | |||
| f8840d89bf | |||
| 813f2f1e12 | |||
| 4a15a89102 | |||
| c707a34f16 | |||
| 0c9010f065 | |||
| 3871299346 | |||
| e2e0b08210 | |||
| 4df0542932 | |||
| 13854e59de | |||
| 574ad42a76 | |||
| 4736fca679 | |||
| 32ae2f8f0d | |||
| d58c0a867d | |||
| 15f8432ce0 | |||
| ae7637acc6 | |||
| ce391a6de8 | |||
| 950835c10b | |||
| 9ba557a5bf | |||
| 439fecd69f | |||
| f02168950f | |||
| 85b91250fb | |||
| 8f2409fc06 | |||
| 58c2235b88 | |||
| 42c5577027 | |||
| 036fe8d6f8 | |||
| ea47d9ff09 | |||
| 81e46f2b52 | |||
| f4bbb1950b | |||
| fd48d45872 | |||
| 92aa9af052 | |||
| 51ebc253aa | |||
| 4fdc7fd210 | |||
| 0bf6c07e8d | |||
| 7a12602699 | |||
| 15a927a9f8 | |||
| 0a2805f23f | |||
| 27ce322690 | |||
| 49aeda86d4 | |||
| cf1df462dc | |||
| dd62581226 | |||
| b369d94bc3 | |||
| f5879cf275 | |||
| 8cc5859a3b | |||
| e86954143b | |||
| a0328b9d68 | |||
| 813a80d6f9 | |||
| ab95bb157e | |||
| 18fd1dbc4a | |||
| a35f7656cb | |||
| ff05f9f48a | |||
| 482c494034 | |||
| 81eafde216 | |||
| 146f5ac80f | |||
| 5f74682cba | |||
| 469e379166 | |||
| f103b228e4 | |||
| d2a31de1be | |||
| 138a537d2b | |||
| c06c861e17 | |||
| 49dbd09167 | |||
| 726f71c8f1 | |||
| 34cbd2605c | |||
| 044bab45ad | |||
| f03ae2cabc | |||
| 3a080ebebe | |||
| b9890d1302 | |||
| 5b2a2a1bc5 | |||
| 2402050f5f | |||
| a97a22d464 | |||
| de9251942c | |||
| 807ffb845a | |||
| e0fc87ef58 | |||
| e876b75d41 | |||
| 229cef8942 | |||
| 6676e06fb5 | |||
| 6e48f8f7ea | |||
| e2efb267f5 | |||
| 684f1a3015 | |||
| 2af9ff7d00 | |||
| ae2265df21 | |||
| 6da297d1d2 | |||
| 6787612071 | |||
| 53d18c7748 | |||
| 8bbe094e70 | |||
| df16ca9a60 | |||
| f1df2d5165 | |||
| 4a58d7f300 | |||
| d6b1216021 | |||
| dadde29bc2 | |||
| 693bf65721 | |||
| 8f3256e46e | |||
| f7de5fe1ed | |||
| 6dd463a7b0 | |||
| ed271bed31 | |||
| 502894ecea | |||
| c185c35c44 | |||
| e8b8f30e3c | |||
| caa2bc1f3c | |||
| 50a6cb5af6 | |||
| 13c33567fd | |||
| af3d06e7d3 | |||
| b74ab2fa0e | |||
| 001fb269b3 | |||
| 262e76c993 | |||
| caf45af4e5 | |||
| cea801e620 | |||
| 19b53e4a4c | |||
| 09f823ac08 | |||
| 5be516b14e | |||
| eb8dc441b9 | |||
| 32a103d86a | |||
| 6d608ab35a | |||
| 334d357189 | |||
| 8363c5c3cf | |||
| cd793d6842 | |||
| 3ae8e0c406 | |||
| 6c93c8b8fa | |||
| efdc84930b | |||
| 6cd6cb1000 | |||
| f4c08ee0d7 | |||
| b5f7f578da | |||
| b172ebdf76 | |||
| 312a43c093 | |||
| e17b4da2a4 | |||
| 003ca30c74 | |||
| 88447bbbf8 | |||
| 1c49eb492a | |||
| 7bdb5bfce6 | |||
| 87615d179e | |||
| ed2d41c225 | |||
| d828a6b9e0 | |||
| d6641f70c9 | |||
| 7b4969e89d | |||
| fc22bf1194 | |||
| 997a6ea419 | |||
| a55cd3b7e9 | |||
| 6b966285a6 | |||
| 5a400fd162 | |||
| 01a5c291e0 | |||
| 4646cd1cf0 | |||
| 2997dff237 | |||
| 2624e44e2f | |||
| 9ec1376d29 | |||
| 9591f1e49c | |||
| ddb90c2e41 | |||
| e97571059c | |||
| 3a6d5fc22a | |||
| a542d319f7 | |||
| 4286a51bf4 | |||
| 6893c833e4 | 
							
								
								
									
										6
									
								
								.changes/unreleased/Feature-20231218-153151.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Feature-20231218-153151.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| kind: Feature | ||||
| body: Create new filter for persons having a participation in an accompanying period | ||||
|   during a certain time span | ||||
| time: 2023-12-18T15:31:51.489901829+01:00 | ||||
| custom: | ||||
|   Issue: "231" | ||||
							
								
								
									
										6
									
								
								.changes/unreleased/Feature-20240122-124849.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Feature-20240122-124849.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| kind: Feature | ||||
| body: '[Export][List of accompanyign period] Add two columns: the list of persons | ||||
|   participating to the period, and their ids' | ||||
| time: 2024-01-22T12:48:49.824833412+01:00 | ||||
| custom: | ||||
|   Issue: "241" | ||||
							
								
								
									
										5
									
								
								.changes/unreleased/Feature-20240129-133319.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changes/unreleased/Feature-20240129-133319.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| kind: Feature | ||||
| body: 'Add capability to generate export about change of steps of accompanying period, and generate exports for this' | ||||
| time: 2024-01-29T13:33:19.190365565+01:00 | ||||
| custom: | ||||
|   Issue: "244" | ||||
							
								
								
									
										5
									
								
								.changes/unreleased/Feature-20240207-103951.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changes/unreleased/Feature-20240207-103951.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| kind: Feature | ||||
| body: 'Export: group accompanying period by person participating' | ||||
| time: 2024-02-07T10:39:51.97331052+01:00 | ||||
| custom: | ||||
|   Issue: "253" | ||||
							
								
								
									
										5
									
								
								.changes/unreleased/Feature-20240207-114629.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changes/unreleased/Feature-20240207-114629.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| kind: Feature | ||||
| body: 'Export: add filter for courses not linked to a reference address' | ||||
| time: 2024-02-07T11:46:29.491027007+01:00 | ||||
| custom: | ||||
|   Issue: "243" | ||||
							
								
								
									
										5
									
								
								.changes/unreleased/Feature-20240207-164038.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changes/unreleased/Feature-20240207-164038.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| kind: Feature | ||||
| body: Allow to group activities linked with accompanying period by reason | ||||
| time: 2024-02-07T16:40:38.408575109+01:00 | ||||
| custom: | ||||
|   Issue: "229" | ||||
							
								
								
									
										6
									
								
								.changes/unreleased/Fixed-20231129-113138.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Fixed-20231129-113138.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| kind: Fixed | ||||
| body: Fix error in logs about wrong typing of eventArgs in onEditNotificationComment | ||||
|   method | ||||
| time: 2023-11-29T11:31:38.933538592+01:00 | ||||
| custom: | ||||
|   Issue: "220" | ||||
							
								
								
									
										6
									
								
								.changes/unreleased/Fixed-20240130-140301.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Fixed-20240130-140301.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| kind: Fixed | ||||
| body: Fix the conditions upon which social actions should be optional or required | ||||
|   in relation to social issues within the activity creation form | ||||
| time: 2024-01-30T14:03:01.942955636+01:00 | ||||
| custom: | ||||
|   Issue: "256" | ||||
| @@ -34,6 +34,8 @@ variables: | ||||
|     DEFAULT_CARRIER_CODE: BE | ||||
|     # force a timezone | ||||
|     TZ: Europe/Brussels | ||||
|     # avoid direct deprecations (using symfony phpunit bridge: https://symfony.com/doc/4.x/components/phpunit_bridge.html#internal-deprecations | ||||
|     SYMFONY_DEPRECATIONS_HELPER: max[total]=99999999&max[self]=0&max[direct]=0&verbose=0 | ||||
|  | ||||
| stages: | ||||
|     - Composer install | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
|     ], | ||||
|     "require": { | ||||
|         "php": "^8.2", | ||||
|         "ext-dom": "*", | ||||
|         "ext-json": "*", | ||||
|         "ext-openssl": "*", | ||||
|         "ext-redis": "*", | ||||
|   | ||||
| @@ -48,7 +48,7 @@ Clone or download the chill-skeleton project and `cd` into the main directory. | ||||
|  | ||||
| .. code-block:: bash | ||||
|  | ||||
|    git clone https://gitlab.com/Chill-Projet/chill-skeleton-basic.git | ||||
|    git clone https://gitea.champs-libres.be/Chill-project/chill-skeleton-basic.git | ||||
|    cd chill-skeleton-basic | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -5,72 +5,74 @@ Add condition with distinct alias on each export join clauses (Indicators + Filt | ||||
|  | ||||
| These are alias conventions : | ||||
|  | ||||
| | Entity                                  | Join                                    | Attribute                                  | Alias                                  | | ||||
| |:----------------------------------------|:----------------------------------------|:-------------------------------------------|:---------------------------------------| | ||||
| | AccompanyingPeriod::class               |                                         |                                            | acp                                    | | ||||
| |                                         | AccompanyingPeriodWork::class           | acp.works                                  | acpw                                   | | ||||
| |                                         | AccompanyingPeriodParticipation::class  | acp.participations                         | acppart                                | | ||||
| |                                         | Location::class                         | acp.administrativeLocation                 | acploc                                 | | ||||
| |                                         | ClosingMotive::class                    | acp.closingMotive                          | acpmotive                              | | ||||
| |                                         | UserJob::class                          | acp.job                                    | acpjob                                 | | ||||
| |                                         | Origin::class                           | acp.origin                                 | acporigin                              | | ||||
| |                                         | Scope::class                            | acp.scopes                                 | acpscope                               | | ||||
| |                                         | SocialIssue::class                      | acp.socialIssues                           | acpsocialissue                         | | ||||
| |                                         | User::class                             | acp.user                                   | acpuser                                | | ||||
| |                                         | AccompanyingPeriopStepHistory::class    | acp.stepHistories                          | acpstephistories                       | | ||||
| |                                         | AccompanyingPeriodInfo::class           | not existing (using custom WITH clause)    | acpinfo                                | | ||||
| | AccompanyingPeriodWork::class           |                                         |                                            | acpw                                   | | ||||
| |                                         | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations     | workeval                               | | ||||
| |                                         | SocialAction::class                     | acpw.socialAction                          | acpwsocialaction                       | | ||||
| |                                         | Goal::class                             | acpw.goals                                 | goal                                   | | ||||
| |                                         | Result::class                           | acpw.results                               | result                                 | | ||||
| | AccompanyingPeriodParticipation::class  |                                         |                                            | acppart                                | | ||||
| |                                         | Person::class                           | acppart.person                             | partperson                             | | ||||
| | AccompanyingPeriodWorkEvaluation::class |                                         |                                            | workeval                               | | ||||
| |                                         | Evaluation::class                       | workeval.evaluation                        | eval                                   | | ||||
| | AccompanyingPeriodInfo::class           |                                         |                                            | acpinfo                                | | ||||
| |                                         | User::class                             | acpinfo.user                               | acpinfo_user                           | | ||||
| | Goal::class                             |                                         |                                            | goal                                   | | ||||
| |                                         | Result::class                           | goal.results                               | goalresult                             | | ||||
| | Person::class                           |                                         |                                            | person                                 | | ||||
| |                                         | Center::class                           | person.center                              | center                                 | | ||||
| |                                         | HouseholdMember::class                  | partperson.householdParticipations         | householdmember                        | | ||||
| |                                         | MaritalStatus::class                    | person.maritalStatus                       | personmarital                          | | ||||
| |                                         | VendeePerson::class                     |                                            | vp                                     | | ||||
| |                                         | VendeePersonMineur::class               |                                            | vpm                                    | | ||||
| |                                         | CurrentPersonAddress::class             | person.currentPersonAddress                | currentPersonAddress (on a given date) | | ||||
| | ResidentialAddress::class               |                                         |                                            | resaddr                                | | ||||
| |                                         | ThirdParty::class                       | resaddr.hostThirdParty                     | tparty                                 | | ||||
| | ThirdParty::class                       |                                         |                                            | tparty                                 | | ||||
| |                                         | ThirdPartyCategory::class               | tparty.categories                          | tpartycat                              | | ||||
| | HouseholdMember::class                  |                                         |                                            | householdmember                        | | ||||
| |                                         | Household::class                        | householdmember.household                  | household                              | | ||||
| |                                         | Person::class                           | householdmember.person                     | memberperson                           | | ||||
| |                                         |                                         | memberperson.center                        | membercenter                           | | ||||
| | Household::class                        |                                         |                                            | household                              | | ||||
| |                                         | HouseholdComposition::class             | household.compositions                     | composition                            | | ||||
| | Activity::class                         |                                         |                                            | activity                               | | ||||
| |                                         | Person::class                           | activity.person                            | actperson                              | | ||||
| |                                         | AccompanyingPeriod::class               | activity.accompanyingPeriod                | acp                                    | | ||||
| |                                         | Person::class                           | activity\_person\_having\_activity.person  | person\_person\_having\_activity       | | ||||
| |                                         | ActivityReason::class                   | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity      | | ||||
| |                                         | ActivityType::class                     | activity.activityType                      | acttype                                | | ||||
| |                                         | Location::class                         | activity.location                          | actloc                                 | | ||||
| |                                         | SocialAction::class                     | activity.socialActions                     | actsocialaction                        | | ||||
| |                                         | SocialIssue::class                      | activity.socialIssues                      | actsocialssue                          | | ||||
| |                                         | ThirdParty::class                       | activity.thirdParties                      | acttparty                              | | ||||
| |                                         | User::class                             | activity.user                              | actuser                                | | ||||
| |                                         | User::class                             | activity.users                             | actusers                               | | ||||
| |                                         | ActivityReason::class                   | activity.reasons                           | actreasons                             | | ||||
| |                                         | Center::class                           | actperson.center                           | actcenter                              | | ||||
| |                                         | Person::class                           | activity.createdBy                         | actcreator                             | | ||||
| | ActivityReason::class                   |                                         |                                            | actreasons                             | | ||||
| |                                         | ActivityReasonCategory::class           | actreason.category                         | actreasoncat                           | | ||||
| | Calendar::class                         |                                         |                                            | cal                                    | | ||||
| |                                         | CancelReason::class                     | cal.cancelReason                           | calcancel                              | | ||||
| |                                         | Location::class                         | cal.location                               | calloc                                 | | ||||
| |                                         | User::class                             | cal.user                                   | caluser                                | | ||||
| | VendeePerson::class                     |                                         |                                            | vp                                     | | ||||
| |                                         | SituationProfessionelle::class          | vp.situationProfessionelle                 | vpprof                                 | | ||||
| |                                         | StatutLogement::class                   | vp.statutLogement                          | vplog                                  | | ||||
| |                                         | TempsDeTravail::class                   | vp.tempsDeTravail                          | vptt                                   | | ||||
| | Entity                                  | Join                                    | Attribute                                  | Alias                                      | | ||||
| |:----------------------------------------|:----------------------------------------|:-------------------------------------------|:-------------------------------------------| | ||||
| | AccompanyingPeriodStepHistory::class    |                                         |                                            | acpstephistory (contexte ACP_STEP_HISTORY) | | ||||
| |                                         | AccompanyingPeriod::class               | acpstephistory.period                      | acp                                        | | ||||
| | AccompanyingPeriod::class               |                                         |                                            | acp                                        | | ||||
| |                                         | AccompanyingPeriodWork::class           | acp.works                                  | acpw                                       | | ||||
| |                                         | AccompanyingPeriodParticipation::class  | acp.participations                         | acppart                                    | | ||||
| |                                         | Location::class                         | acp.administrativeLocation                 | acploc                                     | | ||||
| |                                         | ClosingMotive::class                    | acp.closingMotive                          | acpmotive                                  | | ||||
| |                                         | UserJob::class                          | acp.job                                    | acpjob                                     | | ||||
| |                                         | Origin::class                           | acp.origin                                 | acporigin                                  | | ||||
| |                                         | Scope::class                            | acp.scopes                                 | acpscope                                   | | ||||
| |                                         | SocialIssue::class                      | acp.socialIssues                           | acpsocialissue                             | | ||||
| |                                         | User::class                             | acp.user                                   | acpuser                                    | | ||||
| |                                         | AccompanyingPeriopStepHistory::class    | acp.stepHistories                          | acpstephistories                           | | ||||
| |                                         | AccompanyingPeriodInfo::class           | not existing (using custom WITH clause)    | acpinfo                                    | | ||||
| | AccompanyingPeriodWork::class           |                                         |                                            | acpw                                       | | ||||
| |                                         | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations     | workeval                                   | | ||||
| |                                         | SocialAction::class                     | acpw.socialAction                          | acpwsocialaction                           | | ||||
| |                                         | Goal::class                             | acpw.goals                                 | goal                                       | | ||||
| |                                         | Result::class                           | acpw.results                               | result                                     | | ||||
| | AccompanyingPeriodParticipation::class  |                                         |                                            | acppart                                    | | ||||
| |                                         | Person::class                           | acppart.person                             | partperson                                 | | ||||
| | AccompanyingPeriodWorkEvaluation::class |                                         |                                            | workeval                                   | | ||||
| |                                         | Evaluation::class                       | workeval.evaluation                        | eval                                       | | ||||
| | AccompanyingPeriodInfo::class           |                                         |                                            | acpinfo                                    | | ||||
| |                                         | User::class                             | acpinfo.user                               | acpinfo_user                               | | ||||
| | Goal::class                             |                                         |                                            | goal                                       | | ||||
| |                                         | Result::class                           | goal.results                               | goalresult                                 | | ||||
| | Person::class                           |                                         |                                            | person                                     | | ||||
| |                                         | Center::class                           | person.center                              | center                                     | | ||||
| |                                         | HouseholdMember::class                  | partperson.householdParticipations         | householdmember                            | | ||||
| |                                         | MaritalStatus::class                    | person.maritalStatus                       | personmarital                              | | ||||
| |                                         | VendeePerson::class                     |                                            | vp                                         | | ||||
| |                                         | VendeePersonMineur::class               |                                            | vpm                                        | | ||||
| |                                         | CurrentPersonAddress::class             | person.currentPersonAddress                | currentPersonAddress (on a given date)     | | ||||
| | ResidentialAddress::class               |                                         |                                            | resaddr                                    | | ||||
| |                                         | ThirdParty::class                       | resaddr.hostThirdParty                     | tparty                                     | | ||||
| | ThirdParty::class                       |                                         |                                            | tparty                                     | | ||||
| |                                         | ThirdPartyCategory::class               | tparty.categories                          | tpartycat                                  | | ||||
| | HouseholdMember::class                  |                                         |                                            | householdmember                            | | ||||
| |                                         | Household::class                        | householdmember.household                  | household                                  | | ||||
| |                                         | Person::class                           | householdmember.person                     | memberperson                               | | ||||
| |                                         |                                         | memberperson.center                        | membercenter                               | | ||||
| | Household::class                        |                                         |                                            | household                                  | | ||||
| |                                         | HouseholdComposition::class             | household.compositions                     | composition                                | | ||||
| | Activity::class                         |                                         |                                            | activity                                   | | ||||
| |                                         | Person::class                           | activity.person                            | actperson                                  | | ||||
| |                                         | AccompanyingPeriod::class               | activity.accompanyingPeriod                | acp                                        | | ||||
| |                                         | Person::class                           | activity\_person\_having\_activity.person  | person\_person\_having\_activity           | | ||||
| |                                         | ActivityReason::class                   | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity          | | ||||
| |                                         | ActivityType::class                     | activity.activityType                      | acttype                                    | | ||||
| |                                         | Location::class                         | activity.location                          | actloc                                     | | ||||
| |                                         | SocialAction::class                     | activity.socialActions                     | actsocialaction                            | | ||||
| |                                         | SocialIssue::class                      | activity.socialIssues                      | actsocialssue                              | | ||||
| |                                         | ThirdParty::class                       | activity.thirdParties                      | acttparty                                  | | ||||
| |                                         | User::class                             | activity.user                              | actuser                                    | | ||||
| |                                         | User::class                             | activity.users                             | actusers                                   | | ||||
| |                                         | ActivityReason::class                   | activity.reasons                           | actreasons                                 | | ||||
| |                                         | Center::class                           | actperson.center                           | actcenter                                  | | ||||
| |                                         | Person::class                           | activity.createdBy                         | actcreator                                 | | ||||
| | ActivityReason::class                   |                                         |                                            | actreasons                                 | | ||||
| |                                         | ActivityReasonCategory::class           | actreason.category                         | actreasoncat                               | | ||||
| | Calendar::class                         |                                         |                                            | cal                                        | | ||||
| |                                         | CancelReason::class                     | cal.cancelReason                           | calcancel                                  | | ||||
| |                                         | Location::class                         | cal.location                               | calloc                                     | | ||||
| |                                         | User::class                             | cal.user                                   | caluser                                    | | ||||
| | VendeePerson::class                     |                                         |                                            | vp                                         | | ||||
| |                                         | SituationProfessionelle::class          | vp.situationProfessionelle                 | vpprof                                     | | ||||
| |                                         | StatutLogement::class                   | vp.statutLogement                          | vplog                                      | | ||||
| |                                         | TempsDeTravail::class                   | vp.tempsDeTravail                          | vptt                                       | | ||||
|   | ||||
| @@ -14,8 +14,8 @@ | ||||
|     "@ckeditor/ckeditor5-vue": "^4.0.1", | ||||
|     "@symfony/webpack-encore": "^4.1.0", | ||||
|     "@tsconfig/node14": "^1.0.1", | ||||
|     "@types/dompurify": "^3.0.5", | ||||
|     "bindings": "^1.5.0", | ||||
|     "bootstrap": "^5.0.1", | ||||
|     "chokidar": "^3.5.1", | ||||
|     "fork-awesome": "^1.1.7", | ||||
|     "jquery": "^3.6.0", | ||||
| @@ -34,6 +34,7 @@ | ||||
|     "webpack-cli": "^5.0.1" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "bootstrap": "~5.2.0", | ||||
|     "@fullcalendar/core": "^6.1.4", | ||||
|     "@fullcalendar/daygrid": "^6.1.4", | ||||
|     "@fullcalendar/interaction": "^6.1.4", | ||||
| @@ -42,9 +43,11 @@ | ||||
|     "@fullcalendar/vue3": "^6.1.4", | ||||
|     "@popperjs/core": "^2.9.2", | ||||
|     "@types/leaflet": "^1.9.3", | ||||
|     "dompurify": "^3.0.6", | ||||
|     "dropzone": "^5.7.6", | ||||
|     "es6-promise": "^4.2.8", | ||||
|     "leaflet": "^1.7.1", | ||||
|     "marked": "^9.1.5", | ||||
|     "masonry-layout": "^4.2.2", | ||||
|     "mime": "^3.0.0", | ||||
|     "swagger-ui": "^4.15.5", | ||||
|   | ||||
| @@ -291,7 +291,11 @@ class ActivityType | ||||
|     public function checkSocialActionsVisibility(ExecutionContextInterface $context, mixed $payload) | ||||
|     { | ||||
|         if ($this->socialIssuesVisible !== $this->socialActionsVisible) { | ||||
|             if (!(2 === $this->socialIssuesVisible && 1 === $this->socialActionsVisible)) { | ||||
|             // if social issues are invisible then social actions cannot be optional or required + if social issues are optional then social actions shouldn't be required | ||||
|             if ( | ||||
|                 (0 === $this->socialIssuesVisible && (1 === $this->socialActionsVisible || 2 === $this->socialActionsVisible)) | ||||
|                 || (1 === $this->socialIssuesVisible && 2 === $this->socialActionsVisible) | ||||
|             ) { | ||||
|                 $context | ||||
|                     ->buildViolation('The socialActionsVisible value is not compatible with the socialIssuesVisible value') | ||||
|                     ->atPath('socialActionsVisible') | ||||
|   | ||||
| @@ -57,7 +57,7 @@ final readonly class ByActivityTypeAggregator implements AggregatorInterface | ||||
|  | ||||
|     public function getLabels($key, array $values, mixed $data) | ||||
|     { | ||||
|         return function (null|int|string $value): string { | ||||
|         return function (int|string|null $value): string { | ||||
|             if ('_header' === $value) { | ||||
|                 return 'export.aggregator.acp.by_activity_type.activity_type'; | ||||
|             } | ||||
|   | ||||
| @@ -35,7 +35,7 @@ final readonly class ActivityPresenceAggregator implements AggregatorInterface | ||||
|  | ||||
|     public function getLabels($key, array $values, mixed $data) | ||||
|     { | ||||
|         return function (null|int|string $value): string { | ||||
|         return function (int|string|null $value): string { | ||||
|             if ('_header' === $value) { | ||||
|                 return 'export.aggregator.activity.by_activity_presence.header'; | ||||
|             } | ||||
|   | ||||
| @@ -9,7 +9,7 @@ declare(strict_types=1); | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
| 
 | ||||
| namespace Chill\ActivityBundle\Export\Aggregator\PersonAggregators; | ||||
| namespace Chill\ActivityBundle\Export\Aggregator; | ||||
| 
 | ||||
| use Chill\ActivityBundle\Export\Declarations; | ||||
| use Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository; | ||||
| @@ -25,8 +25,11 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; | ||||
| 
 | ||||
| class ActivityReasonAggregator implements AggregatorInterface, ExportElementValidatedInterface | ||||
| { | ||||
|     public function __construct(protected ActivityReasonCategoryRepository $activityReasonCategoryRepository, protected ActivityReasonRepository $activityReasonRepository, protected TranslatableStringHelper $translatableStringHelper) | ||||
|     { | ||||
|     public function __construct( | ||||
|         protected ActivityReasonCategoryRepository $activityReasonCategoryRepository, | ||||
|         protected ActivityReasonRepository $activityReasonRepository, | ||||
|         protected TranslatableStringHelper $translatableStringHelper | ||||
|     ) { | ||||
|     } | ||||
| 
 | ||||
|     public function addRole(): ?string | ||||
| @@ -51,7 +54,7 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali | ||||
| 
 | ||||
|         // make a jointure only if needed
 | ||||
|         if (!\in_array('actreasons', $qb->getAllAliases(), true)) { | ||||
|             $qb->innerJoin('activity.reasons', 'actreasons'); | ||||
|             $qb->leftJoin('activity.reasons', 'actreasons'); | ||||
|         } | ||||
| 
 | ||||
|         // join category if necessary
 | ||||
| @@ -62,19 +65,12 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // add the "group by" part
 | ||||
|         $groupBy = $qb->getDQLPart('groupBy'); | ||||
| 
 | ||||
|         if (\count($groupBy) > 0) { | ||||
|             $qb->addGroupBy($alias); | ||||
|         } else { | ||||
|             $qb->groupBy($alias); | ||||
|         } | ||||
|         $qb->addGroupBy($alias); | ||||
|     } | ||||
| 
 | ||||
|     public function applyOn(): string | ||||
|     { | ||||
|         return Declarations::ACTIVITY_PERSON; | ||||
|         return Declarations::ACTIVITY; | ||||
|     } | ||||
| 
 | ||||
|     public function buildForm(FormBuilderInterface $builder) | ||||
| @@ -96,7 +92,9 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali | ||||
| 
 | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|         return [ | ||||
|             'level' => 'reasons', | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     public function getLabels($key, array $values, $data) | ||||
| @@ -58,7 +58,7 @@ class ActivityTypeAggregator implements AggregatorInterface | ||||
|  | ||||
|     public function getLabels($key, array $values, $data): \Closure | ||||
|     { | ||||
|         return function (null|int|string $value): string { | ||||
|         return function (int|string|null $value): string { | ||||
|             if ('_header' === $value) { | ||||
|                 return 'Activity type'; | ||||
|             } | ||||
|   | ||||
| @@ -36,14 +36,14 @@ final readonly class ActivityDocumentACLAwareRepository implements ActivityDocum | ||||
|     ) { | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQueryInterface | ||||
|     public function buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface | ||||
|     { | ||||
|         $query = $this->buildBaseFetchQueryActivityDocumentLinkedToPersonFromPersonContext($person, $startDate, $endDate, $content); | ||||
|  | ||||
|         return $this->addFetchQueryByPersonACL($query, $person); | ||||
|     } | ||||
|  | ||||
|     public function buildBaseFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery | ||||
|     public function buildBaseFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery | ||||
|     { | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
|         $activityMetadata = $this->em->getClassMetadata(Activity::class); | ||||
| @@ -72,7 +72,7 @@ final readonly class ActivityDocumentACLAwareRepository implements ActivityDocum | ||||
|         return $this->addWhereClauses($query, $startDate, $endDate, $content); | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery | ||||
|     public function buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery | ||||
|     { | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
|         $activityMetadata = $this->em->getClassMetadata(Activity::class); | ||||
| @@ -123,7 +123,7 @@ final readonly class ActivityDocumentACLAwareRepository implements ActivityDocum | ||||
|         return $this->addWhereClauses($query, $startDate, $endDate, $content); | ||||
|     } | ||||
|  | ||||
|     private function addWhereClauses(FetchQuery $query, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery | ||||
|     private function addWhereClauses(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery | ||||
|     { | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
|  | ||||
|   | ||||
| @@ -25,12 +25,12 @@ interface ActivityDocumentACLAwareRepositoryInterface | ||||
|      * | ||||
|      * This method must check the rights to see a document: the user must be allowed to see the given activities | ||||
|      */ | ||||
|     public function buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQueryInterface; | ||||
|     public function buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface; | ||||
|  | ||||
|     /** | ||||
|      * Return a fetch query for querying document's activities for an activity in accompanying periods, but for a given person. | ||||
|      * | ||||
|      * This method must check the rights to see a document: the user must be allowed to see the given accompanying periods | ||||
|      */ | ||||
|     public function buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery; | ||||
|     public function buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery; | ||||
| } | ||||
|   | ||||
| @@ -34,7 +34,7 @@ class ActivityPresenceRepository implements ActivityPresenceRepositoryInterface | ||||
|         return $this->repository->findAll(); | ||||
|     } | ||||
|  | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -25,7 +25,7 @@ interface ActivityPresenceRepositoryInterface | ||||
|     /** | ||||
|      * @return array|ActivityPresence[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array; | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array; | ||||
|  | ||||
|     public function findOneBy(array $criteria): ?ActivityPresence; | ||||
|  | ||||
|   | ||||
| @@ -48,7 +48,7 @@ final class ActivityTypeRepository implements ActivityTypeRepositoryInterface | ||||
|     /** | ||||
|      * @return array|ActivityType[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -37,7 +37,7 @@ final readonly class AccompanyingPeriodActivityGenericDocProvider implements Gen | ||||
|     ) { | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
|         $activityMetadata = $this->em->getClassMetadata(Activity::class); | ||||
| @@ -100,7 +100,7 @@ final readonly class AccompanyingPeriodActivityGenericDocProvider implements Gen | ||||
|         return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $person); | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForPerson(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         return $this->activityDocumentACLAwareRepository | ||||
|             ->buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext($person, $startDate, $endDate, $content); | ||||
|   | ||||
| @@ -28,7 +28,7 @@ final readonly class PersonActivityGenericDocProvider implements GenericDocForPe | ||||
|     ) { | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForPerson(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         return $this->personActivityDocumentACLAwareRepository->buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext( | ||||
|             $person, | ||||
|   | ||||
| @@ -9,10 +9,10 @@ declare(strict_types=1); | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
| 
 | ||||
| namespace Chill\ActivityBundle\Tests\Export\Aggregator\PersonAggregators; | ||||
| namespace Chill\ActivityBundle\Tests\Export\Aggregator; | ||||
| 
 | ||||
| use Chill\ActivityBundle\Entity\Activity; | ||||
| use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator; | ||||
| use Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator; | ||||
| use Chill\MainBundle\Test\Export\AbstractAggregatorTest; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
| use Prophecy\PhpUnit\ProphecyTrait; | ||||
| @@ -33,14 +33,14 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest | ||||
|         self::bootKernel(); | ||||
| 
 | ||||
|         $this->aggregator = self::$container->get(ActivityReasonAggregator::class); | ||||
|         /* | ||||
|                 $request = $this->prophesize() | ||||
|                     ->willExtend(\Symfony\Component\HttpFoundation\Request::class); | ||||
| 
 | ||||
|         $request = $this->prophesize() | ||||
|             ->willExtend(\Symfony\Component\HttpFoundation\Request::class); | ||||
|                 $request->getLocale()->willReturn('fr'); | ||||
| 
 | ||||
|         $request->getLocale()->willReturn('fr'); | ||||
| 
 | ||||
|         self::$container->get('request_stack') | ||||
|             ->push($request->reveal()); | ||||
|                 self::$container->get('request_stack') | ||||
|                     ->push($request->reveal());*/ | ||||
|     } | ||||
| 
 | ||||
|     public function getAggregator() | ||||
| @@ -65,7 +65,12 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest | ||||
|         return [ | ||||
|             $em->createQueryBuilder() | ||||
|                 ->select('count(activity.id)') | ||||
|                 ->from(Activity::class, 'activity'), | ||||
|                 ->from(Activity::class, 'activity') | ||||
|                 ->join('activity.person', 'person'), | ||||
|             $em->createQueryBuilder() | ||||
|                 ->select('count(activity.id)') | ||||
|                 ->from(Activity::class, 'activity') | ||||
|                 ->join('activity.accompanyingPeriod', 'accompanyingPeriod'), | ||||
|             $em->createQueryBuilder() | ||||
|                 ->select('count(activity.id)') | ||||
|                 ->from(Activity::class, 'activity') | ||||
| @@ -157,7 +157,7 @@ final class ActivityVoterTest extends KernelTestCase | ||||
|      * | ||||
|      * @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface | ||||
|      */ | ||||
|     protected function prepareToken(User $user = null) | ||||
|     protected function prepareToken(?User $user = null) | ||||
|     { | ||||
|         $token = $this->prophet->prophesize(); | ||||
|         $token | ||||
|   | ||||
| @@ -153,7 +153,7 @@ services: | ||||
|  | ||||
|  | ||||
|     ## Aggregators | ||||
|     Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator: | ||||
|     Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator: | ||||
|         tags: | ||||
|             - { name: chill.export_aggregator, alias: activity_reason_aggregator } | ||||
|  | ||||
|   | ||||
| @@ -49,7 +49,7 @@ final class AsideActivityController extends CRUDController | ||||
|         return $asideActivity; | ||||
|     } | ||||
|  | ||||
|     protected function buildQueryEntities(string $action, Request $request, FilterOrderHelper $filterOrder = null) | ||||
|     protected function buildQueryEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null) | ||||
|     { | ||||
|         $qb = parent::buildQueryEntities($action, $request); | ||||
|  | ||||
|   | ||||
| @@ -32,7 +32,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface | ||||
|      * | ||||
|      * @Assert\NotBlank | ||||
|      */ | ||||
|     private \Chill\MainBundle\Entity\User $agent; | ||||
|     private User $agent; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Column(type="datetime") | ||||
| @@ -44,7 +44,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface | ||||
|      * | ||||
|      * @ORM\JoinColumn(nullable=false) | ||||
|      */ | ||||
|     private \Chill\MainBundle\Entity\User $createdBy; | ||||
|     private User $createdBy; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Column(type="datetime") | ||||
| @@ -82,7 +82,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface | ||||
|      * | ||||
|      * @ORM\JoinColumn(nullable=false) | ||||
|      */ | ||||
|     private ?\Chill\AsideActivityBundle\Entity\AsideActivityCategory $type = null; | ||||
|     private ?AsideActivityCategory $type = null; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Column(type="datetime", nullable=true) | ||||
| @@ -92,7 +92,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface | ||||
|     /** | ||||
|      * @ORM\ManyToOne(targetEntity=User::class) | ||||
|      */ | ||||
|     private \Chill\MainBundle\Entity\User $updatedBy; | ||||
|     private User $updatedBy; | ||||
|  | ||||
|     public function getAgent(): ?User | ||||
|     { | ||||
|   | ||||
| @@ -49,7 +49,7 @@ class AsideActivityCategoryRepository implements ObjectRepository | ||||
|      * | ||||
|      * @return AsideActivityCategory[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -0,0 +1,66 @@ | ||||
| <?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\Tests\Security\Guard; | ||||
|  | ||||
| use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; | ||||
| use Chill\DocStoreBundle\Security\Guard\DavTokenAuthenticationEventSubscriber; | ||||
| use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTAuthenticatedEvent; | ||||
| use PHPUnit\Framework\TestCase; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; | ||||
|  | ||||
| /** | ||||
|  * @internal | ||||
|  * | ||||
|  * @coversNothing | ||||
|  */ | ||||
| class DavTokenAuthenticationEventSubscriberTest extends TestCase | ||||
| { | ||||
|     public function testOnJWTAuthenticatedWithDavDataInPayload(): void | ||||
|     { | ||||
|         $eventSubscriber = new DavTokenAuthenticationEventSubscriber(); | ||||
|         $token = new class () extends AbstractToken { | ||||
|             public function getCredentials() | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
|         }; | ||||
|         $event = new JWTAuthenticatedEvent([ | ||||
|             'dav' => 1, | ||||
|             'so' => '1234', | ||||
|             'e' => 1, | ||||
|         ], $token); | ||||
|  | ||||
|         $eventSubscriber->onJWTAuthenticated($event); | ||||
|  | ||||
|         self::assertTrue($token->hasAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)); | ||||
|         self::assertTrue($token->hasAttribute(DavTokenAuthenticationEventSubscriber::ACTIONS)); | ||||
|         self::assertEquals('1234', $token->getAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)); | ||||
|         self::assertEquals(StoredObjectRoleEnum::EDIT, $token->getAttribute(DavTokenAuthenticationEventSubscriber::ACTIONS)); | ||||
|     } | ||||
|  | ||||
|     public function testOnJWTAuthenticatedWithDavNoDataInPayload(): void | ||||
|     { | ||||
|         $eventSubscriber = new DavTokenAuthenticationEventSubscriber(); | ||||
|         $token = new class () extends AbstractToken { | ||||
|             public function getCredentials() | ||||
|             { | ||||
|                 return null; | ||||
|             } | ||||
|         }; | ||||
|         $event = new JWTAuthenticatedEvent([], $token); | ||||
|  | ||||
|         $eventSubscriber->onJWTAuthenticated($event); | ||||
|  | ||||
|         self::assertFalse($token->hasAttribute(DavTokenAuthenticationEventSubscriber::STORED_OBJECT)); | ||||
|         self::assertFalse($token->hasAttribute(DavTokenAuthenticationEventSubscriber::ACTIONS)); | ||||
|     } | ||||
| } | ||||
| @@ -132,14 +132,14 @@ abstract class AbstractElement | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     public function setComment(string $comment = null): self | ||||
|     public function setComment(?string $comment = null): self | ||||
|     { | ||||
|         $this->comment = $comment; | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     public function setEndDate(\DateTimeInterface $endDate = null): self | ||||
|     public function setEndDate(?\DateTimeInterface $endDate = null): self | ||||
|     { | ||||
|         if ($endDate instanceof \DateTime) { | ||||
|             $this->endDate = \DateTimeImmutable::createFromMutable($endDate); | ||||
|   | ||||
| @@ -66,7 +66,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface | ||||
|      * | ||||
|      * @return array<ChargeKind> | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -36,7 +36,7 @@ interface ChargeKindRepositoryInterface extends ObjectRepository | ||||
|     /** | ||||
|      * @return array<ChargeKind> | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array; | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array; | ||||
|  | ||||
|     public function findOneBy(array $criteria): ?ChargeKind; | ||||
|  | ||||
|   | ||||
| @@ -71,7 +71,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface | ||||
|      * | ||||
|      * @return list<ResourceKind> | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -36,7 +36,7 @@ interface ResourceKindRepositoryInterface extends ObjectRepository | ||||
|     /** | ||||
|      * @return list<ResourceKind> | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array; | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array; | ||||
|  | ||||
|     public function findOneBy(array $criteria): ?ResourceKind; | ||||
|  | ||||
|   | ||||
| @@ -32,7 +32,7 @@ final class Version20221207105407 extends AbstractMigration implements Container | ||||
|         return 'Use new budget admin entities'; | ||||
|     } | ||||
|  | ||||
|     public function setContainer(ContainerInterface $container = null) | ||||
|     public function setContainer(?ContainerInterface $container = null) | ||||
|     { | ||||
|         $this->container = $container; | ||||
|     } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ namespace Chill\CalendarBundle\Exception; | ||||
|  | ||||
| class UserAbsenceSyncException extends \LogicException | ||||
| { | ||||
|     public function __construct(string $message = '', int $code = 20_230_706, \Throwable $previous = null) | ||||
|     public function __construct(string $message = '', int $code = 20_230_706, ?\Throwable $previous = null) | ||||
|     { | ||||
|         parent::__construct($message, $code, $previous); | ||||
|     } | ||||
|   | ||||
| @@ -33,7 +33,7 @@ final readonly class MSUserAbsenceReader implements MSUserAbsenceReaderInterface | ||||
|     /** | ||||
|      * @throw UserAbsenceSyncException when the data cannot be reached or is not valid from microsoft | ||||
|      */ | ||||
|     public function isUserAbsent(User $user): null|bool | ||||
|     public function isUserAbsent(User $user): bool|null | ||||
|     { | ||||
|         $id = $this->mapCalendarToUser->getUserId($user); | ||||
|  | ||||
|   | ||||
| @@ -18,5 +18,5 @@ interface MSUserAbsenceReaderInterface | ||||
|     /** | ||||
|      * @throw UserAbsenceSyncException when the data cannot be reached or is not valid from microsoft | ||||
|      */ | ||||
|     public function isUserAbsent(User $user): null|bool; | ||||
|     public function isUserAbsent(User $user): bool|null; | ||||
| } | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class MachineHttpClient implements HttpClientInterface | ||||
|  | ||||
|     private readonly HttpClientInterface $decoratedClient; | ||||
|  | ||||
|     public function __construct(private readonly MachineTokenStorage $machineTokenStorage, HttpClientInterface $decoratedClient = null) | ||||
|     public function __construct(private readonly MachineTokenStorage $machineTokenStorage, ?HttpClientInterface $decoratedClient = null) | ||||
|     { | ||||
|         $this->decoratedClient = $decoratedClient ?? \Symfony\Component\HttpClient\HttpClient::create(); | ||||
|     } | ||||
| @@ -68,7 +68,7 @@ class MachineHttpClient implements HttpClientInterface | ||||
|         return $this->decoratedClient->request($method, $url, $options); | ||||
|     } | ||||
|  | ||||
|     public function stream($responses, float $timeout = null): ResponseStreamInterface | ||||
|     public function stream($responses, ?float $timeout = null): ResponseStreamInterface | ||||
|     { | ||||
|         return $this->decoratedClient->stream($responses, $timeout); | ||||
|     } | ||||
|   | ||||
| @@ -178,8 +178,8 @@ class MapCalendarToUser | ||||
|     public function writeSubscriptionMetadata( | ||||
|         User $user, | ||||
|         int $expiration, | ||||
|         string $id = null, | ||||
|         string $secret = null | ||||
|         ?string $id = null, | ||||
|         ?string $secret = null | ||||
|     ): void { | ||||
|         $user->setAttributeByDomain(self::METADATA_KEY, self::EXPIRATION_SUBSCRIPTION_EVENT, $expiration); | ||||
|  | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class OnBehalfOfUserHttpClient | ||||
|  | ||||
|     private readonly HttpClientInterface $decoratedClient; | ||||
|  | ||||
|     public function __construct(private readonly OnBehalfOfUserTokenStorage $tokenStorage, HttpClientInterface $decoratedClient = null) | ||||
|     public function __construct(private readonly OnBehalfOfUserTokenStorage $tokenStorage, ?HttpClientInterface $decoratedClient = null) | ||||
|     { | ||||
|         $this->decoratedClient = $decoratedClient ?? \Symfony\Component\HttpClient\HttpClient::create(); | ||||
|     } | ||||
| @@ -63,7 +63,7 @@ class OnBehalfOfUserHttpClient | ||||
|         return $this->decoratedClient->request($method, $url, $options); | ||||
|     } | ||||
|  | ||||
|     public function stream($responses, float $timeout = null): ResponseStreamInterface | ||||
|     public function stream($responses, ?float $timeout = null): ResponseStreamInterface | ||||
|     { | ||||
|         return $this->decoratedClient->stream($responses, $timeout); | ||||
|     } | ||||
|   | ||||
| @@ -171,7 +171,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function removeCalendar(string $remoteId, array $remoteAttributes, User $user, CalendarRange $associatedCalendarRange = null): void | ||||
|     public function removeCalendar(string $remoteId, array $remoteAttributes, User $user, ?CalendarRange $associatedCalendarRange = null): void | ||||
|     { | ||||
|         if ('' === $remoteId) { | ||||
|             return; | ||||
|   | ||||
| @@ -46,7 +46,7 @@ class NullRemoteCalendarConnector implements RemoteCalendarConnectorInterface | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     public function removeCalendar(string $remoteId, array $remoteAttributes, User $user, CalendarRange $associatedCalendarRange = null): void | ||||
|     public function removeCalendar(string $remoteId, array $remoteAttributes, User $user, ?CalendarRange $associatedCalendarRange = null): void | ||||
|     { | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -47,7 +47,7 @@ interface RemoteCalendarConnectorInterface | ||||
|      */ | ||||
|     public function listEventsForUser(User $user, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate, ?int $offset = 0, ?int $limit = 50): array; | ||||
|  | ||||
|     public function removeCalendar(string $remoteId, array $remoteAttributes, User $user, CalendarRange $associatedCalendarRange = null): void; | ||||
|     public function removeCalendar(string $remoteId, array $remoteAttributes, User $user, ?CalendarRange $associatedCalendarRange = null): void; | ||||
|  | ||||
|     public function removeCalendarRange(string $remoteId, array $remoteAttributes, User $user): void; | ||||
|  | ||||
|   | ||||
| @@ -159,7 +159,7 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface | ||||
|     /** | ||||
|      * @return array|Calendar[] | ||||
|      */ | ||||
|     public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], int $offset = null, int $limit = null): array | ||||
|     public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array | ||||
|     { | ||||
|         $qb = $this->buildQueryByAccompanyingPeriod($period, $startDate, $endDate)->select('c'); | ||||
|  | ||||
| @@ -178,7 +178,7 @@ class CalendarACLAwareRepository implements CalendarACLAwareRepositoryInterface | ||||
|         return $qb->getQuery()->getResult(); | ||||
|     } | ||||
|  | ||||
|     public function findByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], int $offset = null, int $limit = null): array | ||||
|     public function findByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array | ||||
|     { | ||||
|         $qb = $this->buildQueryByPerson($person, $startDate, $endDate) | ||||
|             ->select('c'); | ||||
|   | ||||
| @@ -46,7 +46,7 @@ interface CalendarACLAwareRepositoryInterface | ||||
|     /** | ||||
|      * @return array|Calendar[] | ||||
|      */ | ||||
|     public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], int $offset = null, int $limit = null): array; | ||||
|     public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array; | ||||
|  | ||||
|     /** | ||||
|      * Return all the calendars which are associated with a person, either on @see{Calendar::person} or within. | ||||
| @@ -58,5 +58,5 @@ interface CalendarACLAwareRepositoryInterface | ||||
|      * | ||||
|      * @return array|Calendar[] | ||||
|      */ | ||||
|     public function findByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], int $offset = null, int $limit = null): array; | ||||
|     public function findByPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?array $orderBy = [], ?int $offset = null, ?int $limit = null): array; | ||||
| } | ||||
|   | ||||
| @@ -35,7 +35,7 @@ class CalendarDocRepository implements ObjectRepository, CalendarDocRepositoryIn | ||||
|         return $this->repository->findAll(); | ||||
|     } | ||||
|  | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null) | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -25,7 +25,7 @@ interface CalendarDocRepositoryInterface | ||||
|     /** | ||||
|      * @return array|CalendarDoc[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null); | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null); | ||||
|  | ||||
|     public function findOneBy(array $criteria): ?CalendarDoc; | ||||
|  | ||||
|   | ||||
| @@ -52,7 +52,7 @@ class CalendarRangeRepository implements ObjectRepository | ||||
|     /** | ||||
|      * @return array|CalendarRange[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null) | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
| @@ -64,8 +64,8 @@ class CalendarRangeRepository implements ObjectRepository | ||||
|         User $user, | ||||
|         \DateTimeImmutable $from, | ||||
|         \DateTimeImmutable $to, | ||||
|         int $limit = null, | ||||
|         int $offset = null | ||||
|         ?int $limit = null, | ||||
|         ?int $offset = null | ||||
|     ): array { | ||||
|         $qb = $this->buildQueryAvailableRangesForUser($user, $from, $to); | ||||
|  | ||||
|   | ||||
| @@ -46,7 +46,7 @@ class CalendarRepository implements ObjectRepository | ||||
|             ->getSingleScalarResult(); | ||||
|     } | ||||
|  | ||||
|     public function createQueryBuilder(string $alias, string $indexBy = null): QueryBuilder | ||||
|     public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder | ||||
|     { | ||||
|         return $this->repository->createQueryBuilder($alias, $indexBy); | ||||
|     } | ||||
| @@ -67,7 +67,7 @@ class CalendarRepository implements ObjectRepository | ||||
|     /** | ||||
|      * @return array|Calendar[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
| @@ -75,7 +75,7 @@ class CalendarRepository implements ObjectRepository | ||||
|     /** | ||||
|      * @return array|Calendar[] | ||||
|      */ | ||||
|     public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $orderBy = null, int $limit = null, int $offset = null): array | ||||
|     public function findByAccompanyingPeriod(AccompanyingPeriod $period, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->findBy( | ||||
|             [ | ||||
| @@ -87,7 +87,7 @@ class CalendarRepository implements ObjectRepository | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public function findByNotificationAvailable(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, int $limit = null, int $offset = null): array | ||||
|     public function findByNotificationAvailable(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         $qb = $this->queryByNotificationAvailable($startDate, $endDate)->select('c'); | ||||
|  | ||||
| @@ -105,7 +105,7 @@ class CalendarRepository implements ObjectRepository | ||||
|     /** | ||||
|      * @return array|Calendar[] | ||||
|      */ | ||||
|     public function findByUser(User $user, \DateTimeImmutable $from, \DateTimeImmutable $to, int $limit = null, int $offset = null): array | ||||
|     public function findByUser(User $user, \DateTimeImmutable $from, \DateTimeImmutable $to, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         $qb = $this->buildQueryByUser($user, $from, $to)->select('c'); | ||||
|  | ||||
|   | ||||
| @@ -41,7 +41,7 @@ class InviteRepository implements ObjectRepository | ||||
|     /** | ||||
|      * @return array|Invite[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null) | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) | ||||
|     { | ||||
|         return $this->entityRepository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -44,7 +44,7 @@ final readonly class AccompanyingPeriodCalendarGenericDocProvider implements Gen | ||||
|     /** | ||||
|      * @throws MappingException | ||||
|      */ | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         $classMetadata = $this->em->getClassMetadata(CalendarDoc::class); | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
| @@ -91,7 +91,7 @@ final readonly class AccompanyingPeriodCalendarGenericDocProvider implements Gen | ||||
|         return $this->security->isGranted(CalendarVoter::SEE, $accompanyingPeriod); | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForPerson(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         $classMetadata = $this->em->getClassMetadata(CalendarDoc::class); | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
|   | ||||
| @@ -40,7 +40,7 @@ final readonly class PersonCalendarGenericDocProvider implements GenericDocForPe | ||||
|     ) { | ||||
|     } | ||||
|  | ||||
|     private function addWhereClausesToQuery(FetchQuery $query, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery | ||||
|     private function addWhereClausesToQuery(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery | ||||
|     { | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
|  | ||||
| @@ -74,7 +74,7 @@ final readonly class PersonCalendarGenericDocProvider implements GenericDocForPe | ||||
|     /** | ||||
|      * @throws MappingException | ||||
|      */ | ||||
|     public function buildFetchQueryForPerson(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         $classMetadata = $this->em->getClassMetadata(CalendarDoc::class); | ||||
|         $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); | ||||
|   | ||||
| @@ -202,8 +202,8 @@ final class CalendarContextTest extends TestCase | ||||
|     } | ||||
|  | ||||
|     private function buildCalendarContext( | ||||
|         EntityManagerInterface $entityManager = null, | ||||
|         NormalizerInterface $normalizer = null | ||||
|         ?EntityManagerInterface $entityManager = null, | ||||
|         ?NormalizerInterface $normalizer = null | ||||
|     ): CalendarContext { | ||||
|         $baseContext = $this->prophesize(BaseContextData::class); | ||||
|         $baseContext->getData(null)->willReturn(['base_context' => 'data']); | ||||
|   | ||||
| @@ -363,7 +363,7 @@ class CustomFieldsGroupController extends AbstractController | ||||
|      * | ||||
|      * @return \Symfony\Component\Form\Form | ||||
|      */ | ||||
|     private function createMakeDefaultForm(CustomFieldsGroup $group = null) | ||||
|     private function createMakeDefaultForm(?CustomFieldsGroup $group = null) | ||||
|     { | ||||
|         return $this->createFormBuilder($group, [ | ||||
|             'method' => 'POST', | ||||
|   | ||||
| @@ -156,7 +156,7 @@ class CustomFieldChoice extends AbstractCustomField | ||||
|         return $serialized; | ||||
|     } | ||||
|  | ||||
|     public function extractOtherValue(CustomField $cf, array $data = null) | ||||
|     public function extractOtherValue(CustomField $cf, ?array $data = null) | ||||
|     { | ||||
|         return $data['_other']; | ||||
|     } | ||||
| @@ -355,7 +355,7 @@ class CustomFieldChoice extends AbstractCustomField | ||||
|      * If the value had an 'allow_other' = true option, the returned value | ||||
|      * **is not** the content of the _other field, but the `_other` string. | ||||
|      */ | ||||
|     private function guessValue(null|array|string $value) | ||||
|     private function guessValue(array|string|null $value) | ||||
|     { | ||||
|         if (null === $value) { | ||||
|             return null; | ||||
|   | ||||
| @@ -38,7 +38,7 @@ class CustomField | ||||
|      *     targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup", | ||||
|      * inversedBy="customFields") | ||||
|      */ | ||||
|     private ?\Chill\CustomFieldsBundle\Entity\CustomFieldsGroup $customFieldGroup = null; | ||||
|     private ?CustomFieldsGroup $customFieldGroup = null; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Id | ||||
| @@ -212,7 +212,7 @@ class CustomField | ||||
|      * | ||||
|      * @return CustomField | ||||
|      */ | ||||
|     public function setCustomFieldsGroup(CustomFieldsGroup $customFieldGroup = null) | ||||
|     public function setCustomFieldsGroup(?CustomFieldsGroup $customFieldGroup = null) | ||||
|     { | ||||
|         $this->customFieldGroup = $customFieldGroup; | ||||
|  | ||||
|   | ||||
| @@ -63,7 +63,7 @@ class Option | ||||
|      * | ||||
|      * @ORM\JoinColumn(nullable=true) | ||||
|      */ | ||||
|     private ?\Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option $parent = null; | ||||
|     private ?Option $parent = null; | ||||
|  | ||||
|     /** | ||||
|      * A json representation of text (multilingual). | ||||
| @@ -182,7 +182,7 @@ class Option | ||||
|     /** | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function setParent(Option $parent = null) | ||||
|     public function setParent(?Option $parent = null) | ||||
|     { | ||||
|         $this->parent = $parent; | ||||
|         $this->key = $parent->getKey(); | ||||
|   | ||||
| @@ -33,7 +33,7 @@ class CustomFieldsDefaultGroup | ||||
|      * | ||||
|      *     sf4 check: option inversedBy="customFields" return inconsistent error mapping !! | ||||
|      */ | ||||
|     private ?\Chill\CustomFieldsBundle\Entity\CustomFieldsGroup $customFieldsGroup = null; | ||||
|     private ?CustomFieldsGroup $customFieldsGroup = null; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Column(type="string", length=255) | ||||
|   | ||||
| @@ -139,7 +139,7 @@ class CustomFieldsGroup | ||||
|     /** | ||||
|      * Get name. | ||||
|      */ | ||||
|     public function getName(string $language = null): array|string | ||||
|     public function getName(?string $language = null): array|string | ||||
|     { | ||||
|         // TODO set this in a service, PLUS twig function | ||||
|         if (null !== $language) { | ||||
|   | ||||
| @@ -84,7 +84,7 @@ class CustomFieldProvider implements ContainerAwareInterface | ||||
|      * | ||||
|      * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() | ||||
|      */ | ||||
|     public function setContainer(ContainerInterface $container = null) | ||||
|     public function setContainer(?ContainerInterface $container = null) | ||||
|     { | ||||
|         if (null === $container) { | ||||
|             throw new \LogicException('container should not be null'); | ||||
|   | ||||
| @@ -25,7 +25,7 @@ final class CustomFieldsHelperTest extends KernelTestCase | ||||
| { | ||||
|     private ?object $cfHelper = null; | ||||
|  | ||||
|     private \Chill\CustomFieldsBundle\Entity\CustomField $randomCFText; | ||||
|     private CustomField $randomCFText; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|   | ||||
| @@ -13,5 +13,5 @@ namespace Chill\DocGeneratorBundle\GeneratorDriver; | ||||
|  | ||||
| interface DriverInterface | ||||
| { | ||||
|     public function generateFromString(string $template, string $resourceType, array $data, string $templateName = null): string; | ||||
|     public function generateFromString(string $template, string $resourceType, array $data, ?string $templateName = null): string; | ||||
| } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace Chill\DocGeneratorBundle\GeneratorDriver\Exception; | ||||
|  */ | ||||
| class TemplateException extends \RuntimeException | ||||
| { | ||||
|     public function __construct(private readonly array $errors, $code = 0, \Throwable $previous = null) | ||||
|     public function __construct(private readonly array $errors, $code = 0, ?\Throwable $previous = null) | ||||
|     { | ||||
|         parent::__construct('Error while generating document from template', $code, $previous); | ||||
|     } | ||||
|   | ||||
| @@ -33,7 +33,7 @@ final class RelatorioDriver implements DriverInterface | ||||
|         $this->url = $parameterBag->get('chill_doc_generator')['driver']['relatorio']['url']; | ||||
|     } | ||||
|  | ||||
|     public function generateFromString(string $template, string $resourceType, array $data, string $templateName = null): string | ||||
|     public function generateFromString(string $template, string $resourceType, array $data, ?string $templateName = null): string | ||||
|     { | ||||
|         $form = new FormDataPart( | ||||
|             [ | ||||
|   | ||||
| @@ -58,7 +58,7 @@ final class DocGeneratorTemplateRepository implements ObjectRepository | ||||
|      * | ||||
|      * @return DocGeneratorTemplate[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
| @@ -85,7 +85,7 @@ final class DocGeneratorTemplateRepository implements ObjectRepository | ||||
|             ->getResult(); | ||||
|     } | ||||
|  | ||||
|     public function findOneBy(array $criteria, array $orderBy = null): ?DocGeneratorTemplate | ||||
|     public function findOneBy(array $criteria, ?array $orderBy = null): ?DocGeneratorTemplate | ||||
|     { | ||||
|         return $this->repository->findOneBy($criteria, $orderBy); | ||||
|     } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ class NormalizeNullValueHelper | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public function normalize(array $attributes, string $format = 'docgen', ?array $context = [], ClassMetadataInterface $classMetadata = null) | ||||
|     public function normalize(array $attributes, string $format = 'docgen', ?array $context = [], ?ClassMetadataInterface $classMetadata = null) | ||||
|     { | ||||
|         $data = []; | ||||
|         $data['isNull'] = true; | ||||
|   | ||||
| @@ -21,7 +21,7 @@ class BaseContextData | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public function getData(User $user = null): array | ||||
|     public function getData(?User $user = null): array | ||||
|     { | ||||
|         $data = []; | ||||
|  | ||||
|   | ||||
| @@ -46,10 +46,10 @@ class Generator implements GeneratorInterface | ||||
|         DocGeneratorTemplate $template, | ||||
|         int $entityId, | ||||
|         array $contextGenerationDataNormalized, | ||||
|         StoredObject $destinationStoredObject = null, | ||||
|         ?StoredObject $destinationStoredObject = null, | ||||
|         bool $isTest = false, | ||||
|         File $testFile = null, | ||||
|         User $creator = null | ||||
|         ?File $testFile = null, | ||||
|         ?User $creator = null | ||||
|     ): ?string { | ||||
|         if ($destinationStoredObject instanceof StoredObject && StoredObject::STATUS_PENDING !== $destinationStoredObject->getStatus()) { | ||||
|             $this->logger->info(self::LOG_PREFIX.'Aborting generation of an already generated document'); | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class GeneratorException extends \RuntimeException | ||||
|     /** | ||||
|      * @param string[] $errors | ||||
|      */ | ||||
|     public function __construct(private readonly array $errors = [], \Throwable $previous = null) | ||||
|     public function __construct(private readonly array $errors = [], ?\Throwable $previous = null) | ||||
|     { | ||||
|         parent::__construct( | ||||
|             'Could not generate the document', | ||||
|   | ||||
| @@ -33,9 +33,9 @@ interface GeneratorInterface | ||||
|         DocGeneratorTemplate $template, | ||||
|         int $entityId, | ||||
|         array $contextGenerationDataNormalized, | ||||
|         StoredObject $destinationStoredObject = null, | ||||
|         ?StoredObject $destinationStoredObject = null, | ||||
|         bool $isTest = false, | ||||
|         File $testFile = null, | ||||
|         User $creator = null | ||||
|         ?File $testFile = null, | ||||
|         ?User $creator = null | ||||
|     ): ?string; | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ namespace Chill\DocGeneratorBundle\Service\Generator; | ||||
|  | ||||
| class RelatedEntityNotFoundException extends \RuntimeException | ||||
| { | ||||
|     public function __construct(string $relatedEntityClass, int $relatedEntityId, \Throwable $previous = null) | ||||
|     public function __construct(string $relatedEntityClass, int $relatedEntityId, ?\Throwable $previous = null) | ||||
|     { | ||||
|         parent::__construct( | ||||
|             sprintf('Related entity not found: %s, %s', $relatedEntityClass, $relatedEntityId), | ||||
|   | ||||
| @@ -56,7 +56,7 @@ final class BaseContextDataTest extends KernelTestCase | ||||
|     } | ||||
|  | ||||
|     private function buildBaseContext( | ||||
|         NormalizerInterface $normalizer = null | ||||
|         ?NormalizerInterface $normalizer = null | ||||
|     ): BaseContextData { | ||||
|         return new BaseContextData( | ||||
|             $normalizer ?? self::$container->get(NormalizerInterface::class) | ||||
|   | ||||
							
								
								
									
										252
									
								
								src/Bundle/ChillDocStoreBundle/Controller/WebdavController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								src/Bundle/ChillDocStoreBundle/Controller/WebdavController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,252 @@ | ||||
| <?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\Dav\Request\PropfindRequestAnalyzer; | ||||
| use Chill\DocStoreBundle\Dav\Response\DavResponse; | ||||
| use Chill\DocStoreBundle\Entity\StoredObject; | ||||
| use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; | ||||
| use Chill\DocStoreBundle\Service\StoredObjectManagerInterface; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use Symfony\Component\HttpFoundation\Response; | ||||
| use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; | ||||
| use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; | ||||
| use Symfony\Component\Routing\Annotation\Route; | ||||
| use Symfony\Component\Security\Core\Security; | ||||
|  | ||||
| /** | ||||
|  * Provide endpoint for editing a document on the desktop using dav. | ||||
|  * | ||||
|  * This controller implements the minimal required methods to edit a document on a desktop software (i.e. LibreOffice) | ||||
|  * and save the document online. | ||||
|  * | ||||
|  * To avoid to ask for a password, the endpoints are protected using a JWT access token, which is inside the | ||||
|  * URL. This avoid the DAV Client (LibreOffice) to keep an access token in query parameter or in some header (which | ||||
|  * they are not able to understand). The JWT Guard is adapted with a dedicated token extractor which is going to read | ||||
|  * the segments (separation of "/"): the first segment must be the string "dav", and the second one must be the JWT. | ||||
|  */ | ||||
| final readonly class WebdavController | ||||
| { | ||||
|     private PropfindRequestAnalyzer $requestAnalyzer; | ||||
|  | ||||
|     public function __construct( | ||||
|         private \Twig\Environment $engine, | ||||
|         private StoredObjectManagerInterface $storedObjectManager, | ||||
|         private Security $security, | ||||
|     ) { | ||||
|         $this->requestAnalyzer = new PropfindRequestAnalyzer(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/", methods={"GET", "HEAD"}, name="chill_docstore_dav_directory_get") | ||||
|      */ | ||||
|     public function getDirectory(StoredObject $storedObject, string $access_token): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         return new DavResponse( | ||||
|             $this->engine->render('@ChillDocStore/Webdav/directory.html.twig', [ | ||||
|                 'stored_object' => $storedObject, | ||||
|                 'access_token' => $access_token, | ||||
|             ]) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/", methods={"OPTIONS"}) | ||||
|      */ | ||||
|     public function optionsDirectory(StoredObject $storedObject): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         $response = (new DavResponse('')) | ||||
|             ->setEtag($this->storedObjectManager->etag($storedObject)) | ||||
|         ; | ||||
|  | ||||
|         // $response->headers->add(['Allow' =>  'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT,PROPPATCH,COPY,MOVE,REPORT,PATCH,POST,TRACE']); | ||||
|         $response->headers->add(['Allow' =>  'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT']); | ||||
|  | ||||
|         return $response; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/", methods={"PROPFIND"}) | ||||
|      */ | ||||
|     public function propfindDirectory(StoredObject $storedObject, string $access_token, Request $request): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         $depth = $request->headers->get('depth'); | ||||
|  | ||||
|         if ('0' !== $depth && '1' !== $depth) { | ||||
|             throw new BadRequestHttpException('only 1 and 0 are accepted for Depth header'); | ||||
|         } | ||||
|  | ||||
|         [$properties, $lastModified, $etag, $length] = $this->parseDavRequest($request->getContent(), $storedObject); | ||||
|  | ||||
|         $response = new DavResponse( | ||||
|             $this->engine->render('@ChillDocStore/Webdav/directory_propfind.xml.twig', [ | ||||
|                 'stored_object' => $storedObject, | ||||
|                 'properties' => $properties, | ||||
|                 'last_modified' => $lastModified, | ||||
|                 'etag' => $etag, | ||||
|                 'content_length' => $length, | ||||
|                 'depth' => (int) $depth, | ||||
|                 'access_token' => $access_token, | ||||
|             ]), | ||||
|             207 | ||||
|         ); | ||||
|  | ||||
|         $response->headers->add([ | ||||
|             'Content-Type' => 'text/xml', | ||||
|         ]); | ||||
|  | ||||
|         return $response; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/d", name="chill_docstore_dav_document_get", methods={"GET"}) | ||||
|      */ | ||||
|     public function getDocument(StoredObject $storedObject): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         return (new DavResponse($this->storedObjectManager->read($storedObject))) | ||||
|             ->setEtag($this->storedObjectManager->etag($storedObject)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/d", methods={"HEAD"}) | ||||
|      */ | ||||
|     public function headDocument(StoredObject $storedObject): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         $response = new DavResponse(''); | ||||
|  | ||||
|         $response->headers->add( | ||||
|             [ | ||||
|                 'Content-Length' => $this->storedObjectManager->getContentLength($storedObject), | ||||
|                 'Content-Type' => $storedObject->getType(), | ||||
|                 'Etag' => $this->storedObjectManager->etag($storedObject), | ||||
|             ] | ||||
|         ); | ||||
|  | ||||
|         return $response; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/d", methods={"OPTIONS"}) | ||||
|      */ | ||||
|     public function optionsDocument(StoredObject $storedObject): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         $response = (new DavResponse('')) | ||||
|             ->setEtag($this->storedObjectManager->etag($storedObject)) | ||||
|         ; | ||||
|  | ||||
|         $response->headers->add(['Allow' =>  'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT']); | ||||
|  | ||||
|         return $response; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/d", methods={"PROPFIND"}) | ||||
|      */ | ||||
|     public function propfindDocument(StoredObject $storedObject, string $access_token, Request $request): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         [$properties, $lastModified, $etag, $length] = $this->parseDavRequest($request->getContent(), $storedObject); | ||||
|  | ||||
|         $response = new DavResponse( | ||||
|             $this->engine->render( | ||||
|                 '@ChillDocStore/Webdav/doc_props.xml.twig', | ||||
|                 [ | ||||
|                     'stored_object' => $storedObject, | ||||
|                     'properties' => $properties, | ||||
|                     'etag' => $etag, | ||||
|                     'last_modified' => $lastModified, | ||||
|                     'content_length' => $length, | ||||
|                     'access_token' => $access_token, | ||||
|                 ] | ||||
|             ), | ||||
|             207 | ||||
|         ); | ||||
|  | ||||
|         $response | ||||
|             ->headers->add([ | ||||
|                 'Content-Type' => 'text/xml', | ||||
|             ]); | ||||
|  | ||||
|         return $response; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @Route("/dav/{access_token}/get/{uuid}/d", methods={"PUT"}) | ||||
|      */ | ||||
|     public function putDocument(StoredObject $storedObject, Request $request): Response | ||||
|     { | ||||
|         if (!$this->security->isGranted(StoredObjectRoleEnum::EDIT->value, $storedObject)) { | ||||
|             throw new AccessDeniedHttpException(); | ||||
|         } | ||||
|  | ||||
|         $this->storedObjectManager->write($storedObject, $request->getContent()); | ||||
|  | ||||
|         return new DavResponse('', Response::HTTP_NO_CONTENT); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array{0: array, 1: \DateTimeInterface, 2: string, 3: int} properties, lastModified, etag, length | ||||
|      */ | ||||
|     private function parseDavRequest(string $content, StoredObject $storedObject): array | ||||
|     { | ||||
|         $xml = new \DOMDocument(); | ||||
|         $xml->loadXML($content); | ||||
|  | ||||
|         $properties = $this->requestAnalyzer->getRequestedProperties($xml); | ||||
|         $requested = array_keys(array_filter($properties, fn ($item) => true === $item)); | ||||
|  | ||||
|         if ( | ||||
|             in_array('lastModified', $requested, true) | ||||
|             || in_array('etag', $requested, true) | ||||
|         ) { | ||||
|             $lastModified = $this->storedObjectManager->getLastModified($storedObject); | ||||
|             $etag = $this->storedObjectManager->etag($storedObject); | ||||
|         } | ||||
|         if (in_array('contentLength', $requested, true)) { | ||||
|             $length = $this->storedObjectManager->getContentLength($storedObject); | ||||
|         } | ||||
|  | ||||
|         return [ | ||||
|             $properties, | ||||
|             $lastModified ?? null, | ||||
|             $etag ?? null, | ||||
|             $length ?? null, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,16 @@ | ||||
| <?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\Dav\Exception; | ||||
|  | ||||
| class ParseRequestException extends \UnexpectedValueException | ||||
| { | ||||
| } | ||||
| @@ -0,0 +1,103 @@ | ||||
| <?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\Dav\Request; | ||||
|  | ||||
| use Chill\DocStoreBundle\Dav\Exception\ParseRequestException; | ||||
|  | ||||
| /** | ||||
|  * @phpstan-type davProperties array{resourceType: bool, contentType: bool, lastModified: bool, creationDate: bool, contentLength: bool, etag: bool, supportedLock: bool, unknowns: list<array{xmlns: string, prop: string}>} | ||||
|  */ | ||||
| class PropfindRequestAnalyzer | ||||
| { | ||||
|     private const KNOWN_PROPS = [ | ||||
|         'resourceType', | ||||
|         'contentType', | ||||
|         'lastModified', | ||||
|         'creationDate', | ||||
|         'contentLength', | ||||
|         'etag', | ||||
|         'supportedLock', | ||||
|     ]; | ||||
|  | ||||
|     /** | ||||
|      * @return davProperties | ||||
|      */ | ||||
|     public function getRequestedProperties(\DOMDocument $request): array | ||||
|     { | ||||
|         $propfinds = $request->getElementsByTagNameNS('DAV:', 'propfind'); | ||||
|  | ||||
|         if (0 === $propfinds->count()) { | ||||
|             throw new ParseRequestException('any propfind element found'); | ||||
|         } | ||||
|  | ||||
|         if (1 < $propfinds->count()) { | ||||
|             throw new ParseRequestException('too much propfind element found'); | ||||
|         } | ||||
|  | ||||
|         $propfind = $propfinds->item(0); | ||||
|  | ||||
|         if (0 === $propfind->childNodes->count()) { | ||||
|             throw new ParseRequestException('no element under propfind'); | ||||
|         } | ||||
|  | ||||
|         $unknows = []; | ||||
|         $props = []; | ||||
|  | ||||
|         foreach ($propfind->childNodes->getIterator() as $prop) { | ||||
|             /** @var \DOMNode $prop */ | ||||
|             if (XML_ELEMENT_NODE !== $prop->nodeType) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if ('propname' === $prop->nodeName) { | ||||
|                 return $this->baseProps(true); | ||||
|             } | ||||
|  | ||||
|             foreach ($prop->childNodes->getIterator() as $getProp) { | ||||
|                 if (XML_ELEMENT_NODE !== $getProp->nodeType) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 if ('DAV:' !== $getProp->lookupNamespaceURI(null)) { | ||||
|                     $unknows[] = ['xmlns' => $getProp->lookupNamespaceURI(null), 'prop' => $getProp->nodeName]; | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 $props[] = match ($getProp->nodeName) { | ||||
|                     'resourcetype' => 'resourceType', | ||||
|                     'getcontenttype' => 'contentType', | ||||
|                     'getlastmodified' => 'lastModified', | ||||
|                     default => '', | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $props = array_filter(array_values($props), fn (string $item) => '' !== $item); | ||||
|  | ||||
|         return [...$this->baseProps(false), ...array_combine($props, array_fill(0, count($props), true)), 'unknowns' => $unknows]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return davProperties | ||||
|      */ | ||||
|     private function baseProps(bool $default = false): array | ||||
|     { | ||||
|         return | ||||
|             [ | ||||
|                 ...array_combine( | ||||
|                     self::KNOWN_PROPS, | ||||
|                     array_fill(0, count(self::KNOWN_PROPS), $default) | ||||
|                 ), | ||||
|                 'unknowns' => [], | ||||
|             ]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/Bundle/ChillDocStoreBundle/Dav/Response/DavResponse.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/Bundle/ChillDocStoreBundle/Dav/Response/DavResponse.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <?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\Dav\Response; | ||||
|  | ||||
| use Symfony\Component\HttpFoundation\Response; | ||||
|  | ||||
| class DavResponse extends Response | ||||
| { | ||||
|     public function __construct($content = '', int $status = 200, array $headers = []) | ||||
|     { | ||||
|         parent::__construct($content, $status, $headers); | ||||
|  | ||||
|         $this->headers->add(['DAV' => '1']); | ||||
|     } | ||||
| } | ||||
| @@ -37,7 +37,7 @@ class Document implements TrackCreationInterface, TrackUpdateInterface | ||||
|      *     @ORM\JoinColumn(name="category_id_inside_bundle", referencedColumnName="id_inside_bundle") | ||||
|      * }) | ||||
|      */ | ||||
|     private ?\Chill\DocStoreBundle\Entity\DocumentCategory $category = null; | ||||
|     private ?DocumentCategory $category = null; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Column(type="datetime") | ||||
| @@ -61,12 +61,12 @@ class Document implements TrackCreationInterface, TrackUpdateInterface | ||||
|      *     message="Upload a document" | ||||
|      * ) | ||||
|      */ | ||||
|     private ?\Chill\DocStoreBundle\Entity\StoredObject $object = null; | ||||
|     private ?StoredObject $object = null; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\ManyToOne(targetEntity="Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate") | ||||
|      */ | ||||
|     private ?\Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate $template = null; | ||||
|     private ?DocGeneratorTemplate $template = null; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\Column(type="text") | ||||
| @@ -138,7 +138,7 @@ class Document implements TrackCreationInterface, TrackUpdateInterface | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     public function setObject(StoredObject $object = null) | ||||
|     public function setObject(?StoredObject $object = null) | ||||
|     { | ||||
|         $this->object = $object; | ||||
|  | ||||
|   | ||||
| @@ -43,7 +43,7 @@ class PersonDocument extends Document implements HasCenterInterface, HasScopeInt | ||||
|      * | ||||
|      * @var Scope The document's center | ||||
|      */ | ||||
|     private ?\Chill\MainBundle\Entity\Scope $scope = null; | ||||
|     private ?Scope $scope = null; | ||||
|  | ||||
|     public function getCenter() | ||||
|     { | ||||
|   | ||||
| @@ -17,10 +17,10 @@ interface GenericDocForAccompanyingPeriodProviderInterface | ||||
| { | ||||
|     public function buildFetchQueryForAccompanyingPeriod( | ||||
|         AccompanyingPeriod $accompanyingPeriod, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         string $origin = null | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         ?string $origin = null | ||||
|     ): FetchQueryInterface; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -17,10 +17,10 @@ interface GenericDocForPersonProviderInterface | ||||
| { | ||||
|     public function buildFetchQueryForPerson( | ||||
|         Person $person, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         string $origin = null | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         ?string $origin = null | ||||
|     ): FetchQueryInterface; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -43,9 +43,9 @@ final readonly class Manager | ||||
|      */ | ||||
|     public function countDocForAccompanyingPeriod( | ||||
|         AccompanyingPeriod $accompanyingPeriod, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         array $places = [] | ||||
|     ): int { | ||||
|         ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($accompanyingPeriod, $startDate, $endDate, $content, $places); | ||||
| @@ -73,9 +73,9 @@ final readonly class Manager | ||||
|  | ||||
|     public function countDocForPerson( | ||||
|         Person $person, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         array $places = [] | ||||
|     ): int { | ||||
|         ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($person, $startDate, $endDate, $content, $places); | ||||
| @@ -94,9 +94,9 @@ final readonly class Manager | ||||
|         AccompanyingPeriod $accompanyingPeriod, | ||||
|         int $offset = 0, | ||||
|         int $limit = 20, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         array $places = [] | ||||
|     ): iterable { | ||||
|         ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($accompanyingPeriod, $startDate, $endDate, $content, $places); | ||||
| @@ -137,9 +137,9 @@ final readonly class Manager | ||||
|         Person $person, | ||||
|         int $offset = 0, | ||||
|         int $limit = 20, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         array $places = [] | ||||
|     ): iterable { | ||||
|         ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($person, $startDate, $endDate, $content, $places); | ||||
| @@ -183,9 +183,9 @@ final readonly class Manager | ||||
|      */ | ||||
|     private function buildUnionQuery( | ||||
|         AccompanyingPeriod|Person $linked, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         array $places = [], | ||||
|     ): array { | ||||
|         $queries = []; | ||||
|   | ||||
| @@ -34,7 +34,7 @@ final readonly class AccompanyingCourseDocumentGenericDocProvider implements Gen | ||||
|     ) { | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         $classMetadata = $this->entityManager->getClassMetadata(AccompanyingCourseDocument::class); | ||||
|  | ||||
| @@ -59,7 +59,7 @@ final readonly class AccompanyingCourseDocumentGenericDocProvider implements Gen | ||||
|         return $this->security->isGranted(AccompanyingCourseDocumentVoter::SEE, $accompanyingPeriod); | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForPerson(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         $classMetadata = $this->entityManager->getClassMetadata(AccompanyingCourseDocument::class); | ||||
|  | ||||
| @@ -108,7 +108,7 @@ final readonly class AccompanyingCourseDocumentGenericDocProvider implements Gen | ||||
|         return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $person); | ||||
|     } | ||||
|  | ||||
|     private function addWhereClause(FetchQuery $query, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery | ||||
|     private function addWhereClause(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery | ||||
|     { | ||||
|         $classMetadata = $this->entityManager->getClassMetadata(AccompanyingCourseDocument::class); | ||||
|  | ||||
|   | ||||
| @@ -32,10 +32,10 @@ final readonly class PersonDocumentGenericDocProvider implements GenericDocForPe | ||||
|  | ||||
|     public function buildFetchQueryForPerson( | ||||
|         Person $person, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null, | ||||
|         string $origin = null | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null, | ||||
|         ?string $origin = null | ||||
|     ): FetchQueryInterface { | ||||
|         return $this->personDocumentACLAwareRepository->buildFetchQueryForPerson( | ||||
|             $person, | ||||
| @@ -50,7 +50,7 @@ final readonly class PersonDocumentGenericDocProvider implements GenericDocForPe | ||||
|         return $this->security->isGranted(PersonDocumentVoter::SEE, $person); | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null, string $origin = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface | ||||
|     { | ||||
|         return $this->personDocumentACLAwareRepository->buildFetchQueryForAccompanyingPeriod($accompanyingPeriod, $startDate, $endDate, $content); | ||||
|     } | ||||
|   | ||||
| @@ -55,7 +55,7 @@ class AccompanyingCourseDocumentRepository implements ObjectRepository | ||||
|         return $this->repository->findAll(); | ||||
|     } | ||||
|  | ||||
|     public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -41,7 +41,7 @@ class DocumentCategoryRepository implements ObjectRepository | ||||
|         return $this->repository->findAll(); | ||||
|     } | ||||
|  | ||||
|     public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -48,14 +48,14 @@ final readonly class PersonDocumentACLAwareRepository implements PersonDocumentA | ||||
|         return $qb; | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForPerson(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface | ||||
|     { | ||||
|         $query = $this->buildBaseFetchQueryForPerson($person, $startDate, $endDate, $content); | ||||
|  | ||||
|         return $this->addFetchQueryByPersonACL($query, $person); | ||||
|     } | ||||
|  | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $period, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQueryInterface | ||||
|     public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface | ||||
|     { | ||||
|         $personDocMetadata = $this->em->getClassMetadata(PersonDocument::class); | ||||
|         $participationMetadata = $this->em->getClassMetadata(AccompanyingPeriodParticipation::class); | ||||
| @@ -114,7 +114,7 @@ final readonly class PersonDocumentACLAwareRepository implements PersonDocumentA | ||||
|         return $this->addFilterClauses($query, $startDate, $endDate, $content); | ||||
|     } | ||||
|  | ||||
|     public function buildBaseFetchQueryForPerson(Person $person, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery | ||||
|     public function buildBaseFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery | ||||
|     { | ||||
|         $personDocMetadata = $this->em->getClassMetadata(PersonDocument::class); | ||||
|  | ||||
| @@ -134,7 +134,7 @@ final readonly class PersonDocumentACLAwareRepository implements PersonDocumentA | ||||
|         return $this->addFilterClauses($query, $startDate, $endDate, $content); | ||||
|     } | ||||
|  | ||||
|     private function addFilterClauses(FetchQuery $query, \DateTimeImmutable $startDate = null, \DateTimeImmutable $endDate = null, string $content = null): FetchQuery | ||||
|     private function addFilterClauses(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery | ||||
|     { | ||||
|         $personDocMetadata = $this->em->getClassMetadata(PersonDocument::class); | ||||
|  | ||||
|   | ||||
| @@ -29,15 +29,15 @@ interface PersonDocumentACLAwareRepositoryInterface | ||||
|  | ||||
|     public function buildFetchQueryForPerson( | ||||
|         Person $person, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null | ||||
|     ): FetchQueryInterface; | ||||
|  | ||||
|     public function buildFetchQueryForAccompanyingPeriod( | ||||
|         AccompanyingPeriod $period, | ||||
|         \DateTimeImmutable $startDate = null, | ||||
|         \DateTimeImmutable $endDate = null, | ||||
|         string $content = null | ||||
|         ?\DateTimeImmutable $startDate = null, | ||||
|         ?\DateTimeImmutable $endDate = null, | ||||
|         ?string $content = null | ||||
|     ): FetchQueryInterface; | ||||
| } | ||||
|   | ||||
| @@ -39,7 +39,7 @@ readonly class PersonDocumentRepository implements ObjectRepository | ||||
|         return $this->repository->findAll(); | ||||
|     } | ||||
|  | ||||
|     public function findBy(array $criteria, array $orderBy = null, int $limit = null, int $offset = null) | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -44,7 +44,7 @@ final class StoredObjectRepository implements ObjectRepository | ||||
|      * | ||||
|      * @return array<int, StoredObject> | ||||
|      */ | ||||
|     public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array | ||||
|     { | ||||
|         return $this->repository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -17,18 +17,22 @@ window.addEventListener('DOMContentLoaded', function (e) { | ||||
|            canEdit: string, | ||||
|            storedObject: string, | ||||
|            buttonSmall: string, | ||||
|            davLink: string, | ||||
|            davLinkExpiration: string, | ||||
|          }; | ||||
|  | ||||
|          const | ||||
|            storedObject = JSON.parse(datasets.storedObject) as StoredObject, | ||||
|            filename = datasets.filename, | ||||
|            canEdit = datasets.canEdit === '1', | ||||
|            small = datasets.buttonSmall === '1' | ||||
|            small = datasets.buttonSmall === '1', | ||||
|            davLink = 'davLink' in datasets && datasets.davLink !== '' ? datasets.davLink : null, | ||||
|            davLinkExpiration = 'davLinkExpiration' in datasets  ? Number.parseInt(datasets.davLinkExpiration) : null | ||||
|            ; | ||||
|  | ||||
|          return { storedObject, filename, canEdit, small }; | ||||
|          return { storedObject, filename, canEdit, small, davLink, davLinkExpiration }; | ||||
|        }, | ||||
|        template: '<document-action-buttons-group :can-edit="canEdit" :filename="filename" :stored-object="storedObject" :small="small" @on-stored-object-status-change="onStoredObjectStatusChange"></document-action-buttons-group>', | ||||
|        template: '<document-action-buttons-group :can-edit="canEdit" :filename="filename" :stored-object="storedObject" :small="small" :dav-link="davLink" :dav-link-expiration="davLinkExpiration" @on-stored-object-status-change="onStoredObjectStatusChange"></document-action-buttons-group>', | ||||
|        methods: { | ||||
|          onStoredObjectStatusChange: function(newStatus: StoredObjectStatusChange): void { | ||||
|            this.$data.storedObject.status = newStatus.status; | ||||
|   | ||||
| @@ -7,6 +7,9 @@ | ||||
|       <li v-if="props.canEdit && is_extension_editable(props.storedObject.type)"> | ||||
|         <wopi-edit-button :stored-object="props.storedObject" :classes="{'dropdown-item': true}" :execute-before-leave="props.executeBeforeLeave"></wopi-edit-button> | ||||
|       </li> | ||||
|       <li v-if="props.canEdit && is_extension_editable(props.storedObject.type) && props.davLink !== undefined && props.davLinkExpiration !== undefined"> | ||||
|         <desktop-edit-button :classes="{'dropdown-item': true}" :edit-link="props.davLink" :expiration-link="props.davLinkExpiration"></desktop-edit-button> | ||||
|       </li> | ||||
|       <li v-if="props.storedObject.type != 'application/pdf' && is_extension_viewable(props.storedObject.type) && props.canConvertPdf"> | ||||
|         <convert-button :stored-object="props.storedObject" :filename="filename" :classes="{'dropdown-item': true}"></convert-button> | ||||
|       </li> | ||||
| @@ -36,6 +39,7 @@ import { | ||||
|   StoredObjectStatusChange, | ||||
|   WopiEditButtonExecutableBeforeLeaveFunction | ||||
| } from "../types"; | ||||
| import DesktopEditButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DesktopEditButton.vue"; | ||||
|  | ||||
| interface DocumentActionButtonsGroupConfig { | ||||
|   storedObject: StoredObject, | ||||
| @@ -57,6 +61,16 @@ interface DocumentActionButtonsGroupConfig { | ||||
|    * If set, will execute this function before leaving to the editor | ||||
|    */ | ||||
|   executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction, | ||||
|  | ||||
|   /** | ||||
|    * a link to download and edit file using webdav | ||||
|    */ | ||||
|   davLink?: string, | ||||
|  | ||||
|   /** | ||||
|    * the expiration date of the download, as a unix timestamp | ||||
|    */ | ||||
|   davLinkExpiration?: number, | ||||
| } | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
| @@ -68,7 +82,7 @@ const props = withDefaults(defineProps<DocumentActionButtonsGroupConfig>(), { | ||||
|   canEdit: true, | ||||
|   canDownload: true, | ||||
|   canConvertPdf: true, | ||||
|   returnPath: window.location.pathname + window.location.search + window.location.hash, | ||||
|   returnPath: window.location.pathname + window.location.search + window.location.hash | ||||
| }); | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -0,0 +1,66 @@ | ||||
| <script setup lang="ts"> | ||||
|  | ||||
| import Modal from "ChillMainAssets/vuejs/_components/Modal.vue"; | ||||
| import {computed, reactive} from "vue"; | ||||
|  | ||||
| export interface DesktopEditButtonConfig { | ||||
|     editLink: null, | ||||
|     classes: { [k: string]: boolean }, | ||||
|     expirationLink: number|Date, | ||||
| } | ||||
|  | ||||
| interface DesktopEditButtonState { | ||||
|     modalOpened: boolean | ||||
| }; | ||||
|  | ||||
| const state: DesktopEditButtonState = reactive({modalOpened: false}); | ||||
|  | ||||
| const props = defineProps<DesktopEditButtonConfig>(); | ||||
|  | ||||
| const buildCommand = computed<string>(() => 'vnd.libreoffice.command:ofe|u|' + props.editLink); | ||||
|  | ||||
| const editionUntilFormatted = computed<string>(() => { | ||||
|     let d; | ||||
|  | ||||
|     if (props.expirationLink instanceof Date) { | ||||
|         d = props.expirationLink; | ||||
|     } else { | ||||
|         d = new Date(props.expirationLink * 1000); | ||||
|     } | ||||
|     console.log(props.expirationLink); | ||||
|  | ||||
|     return (new Intl.DateTimeFormat(undefined, {'dateStyle': 'long', 'timeStyle': 'medium'})).format(d); | ||||
| }); | ||||
|  | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|     <teleport to="body"> | ||||
|         <modal v-if="state.modalOpened" @close="state.modalOpened=false"> | ||||
|             <template v-slot:body> | ||||
|                 <div class="desktop-edit"> | ||||
|                     <p class="center">Veuillez enregistrer vos modifications avant le</p> | ||||
|                     <p><strong>{{ editionUntilFormatted }}</strong></p> | ||||
|  | ||||
|                     <p><a class="btn btn-primary" :href="buildCommand">Ouvrir le document pour édition</a></p> | ||||
|  | ||||
|                     <p><small>Le document peut être édité uniquement en utilisant Libre Office.</small></p> | ||||
|  | ||||
|                     <p><small>En cas d'échec lors de l'enregistrement, sauver le document sur le poste de travail avant de le déposer à nouveau ici.</small></p> | ||||
|  | ||||
|                     <p><small>Vous pouvez naviguez sur d'autres pages pendant l'édition.</small></p> | ||||
|                 </div> | ||||
|             </template> | ||||
|         </modal> | ||||
|     </teleport> | ||||
|     <a :class="props.classes" @click="state.modalOpened = true"> | ||||
|         <i class="fa fa-desktop"></i> | ||||
|         Éditer sur le bureau | ||||
|     </a> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .desktop-edit { | ||||
|     text-align: center; | ||||
| } | ||||
| </style> | ||||
| @@ -3,5 +3,7 @@ | ||||
|     data-download-buttons | ||||
|     data-stored-object="{{ document_json|json_encode|escape('html_attr') }}" | ||||
|     data-can-edit="{{ can_edit ? '1' : '0' }}" | ||||
|     data-dav-link="{{ dav_link|escape('html_attr') }}" | ||||
|     data-dav-link-expiration="{{ dav_link_expiration|escape('html_attr') }}" | ||||
|     {% if options['small'] is defined %}data-button-small="{{ options['small'] ? '1' : '0' }}"{% endif %} | ||||
|     {% if title|default(document.title)|default(null) is not null %}data-filename="{{ title|default(document.title)|escape('html_attr') }}"{% endif %}></div> | ||||
|   | ||||
| @@ -0,0 +1,12 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <title>Directory for {{ stored_object.uuid }}</title> | ||||
| </head> | ||||
| <body> | ||||
| <ul> | ||||
|     <li><a href="{{ absolute_url(path('chill_docstore_dav_document_get', {'uuid': stored_object.uuid, 'access_token': access_token })) }}">d</a></li> | ||||
| </ul> | ||||
| </body> | ||||
| </html> | ||||
| @@ -0,0 +1,81 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" ?> | ||||
| <d:multistatus xmlns:d="DAV:"> | ||||
|     <d:response> | ||||
|         <d:href>{{ path('chill_docstore_dav_directory_get', { 'uuid': stored_object.uuid, 'access_token': access_token } ) }}</d:href> | ||||
|         {% if properties.resourceType or properties.contentType %} | ||||
|             <d:propstat> | ||||
|                 <d:prop> | ||||
|                     {% if properties.resourceType %} | ||||
|                         <d:resourcetype><d:collection/></d:resourcetype> | ||||
|                     {% endif %} | ||||
|                     {% if properties.contentType %} | ||||
|                         <d:getcontenttype>httpd/unix-directory</d:getcontenttype> | ||||
|                     {% endif %} | ||||
|                 </d:prop> | ||||
|                 <d:status>HTTP/1.1 200 OK</d:status> | ||||
|             </d:propstat> | ||||
|         {% endif %} | ||||
|         {% if properties.unknowns|length > 0 %} | ||||
|             <d:propstat> | ||||
|                 {% for k,u in properties.unknowns %} | ||||
|                     <d:prop {{ ('xmlns:ns' ~ k ~ '="' ~ u.xmlns|e('html_attr') ~ '"')|raw }}> | ||||
|                         <{{ 'ns'~ k ~ ':' ~ u.prop }} /> | ||||
|                     </d:prop> | ||||
|                 {% endfor %} | ||||
|                 <d:status>HTTP/1.1 404 Not Found</d:status> | ||||
|             </d:propstat> | ||||
|         {% endif %} | ||||
|     </d:response> | ||||
|     {% if depth == 1 %} | ||||
|         <d:response> | ||||
|             <d:href>{{ path('chill_docstore_dav_document_get', {'uuid': stored_object.uuid, 'access_token':access_token}) }}</d:href> | ||||
|             {% if properties.lastModified or properties.contentLength or properties.resourceType or properties.etag or properties.contentType or properties.creationDate %} | ||||
|                 <d:propstat> | ||||
|                     <d:prop> | ||||
|                         {% if properties.resourceType %} | ||||
|                             <d:resourcetype/> | ||||
|                         {% endif %} | ||||
|                         {% if properties.creationDate %} | ||||
|                             <d:creationdate /> | ||||
|                         {% endif %} | ||||
|                         {% if properties.lastModified %} | ||||
|                             {%  if last_modified is not same as null %} | ||||
|                                 <d:getlastmodified>{{  last_modified.format(constant('DATE_RSS')) }}</d:getlastmodified> | ||||
|                             {% else %} | ||||
|                                 <d:getlastmodified /> | ||||
|                             {% endif %} | ||||
|                         {% endif %} | ||||
|                         {% if properties.contentLength %} | ||||
|                             {%  if content_length is not same as null %} | ||||
|                                 <d:getcontentlength>{{ content_length }}</d:getcontentlength> | ||||
|                             {% else %} | ||||
|                                 <d:getcontentlength /> | ||||
|                             {% endif %} | ||||
|                         {% endif %} | ||||
|                         {% if properties.etag %} | ||||
|                             {% if etag is not same as null %} | ||||
|                                 <d:getetag>"{{ etag }}"</d:getetag> | ||||
|                             {% else %} | ||||
|                                 <d:getetag /> | ||||
|                             {% endif %} | ||||
|                         {% endif %} | ||||
|                         {% if properties.contentType %} | ||||
|                             <d:getcontenttype>{{ stored_object.type }}</d:getcontenttype> | ||||
|                         {% endif %} | ||||
|                     </d:prop> | ||||
|                     <d:status>HTTP/1.1 200 OK</d:status> | ||||
|                 </d:propstat> | ||||
|             {% endif %} | ||||
|             {% if properties.unknowns|length > 0 %} | ||||
|                 <d:propstat> | ||||
|                     {% for k,u in properties.unknowns %} | ||||
|                         <d:prop {{ ('xmlns:ns' ~ k ~ '="' ~ u.xmlns|e('html_attr') ~ '"')|raw }}> | ||||
|                             <{{ 'ns'~ k ~ ':' ~ u.prop }} /> | ||||
|                         </d:prop> | ||||
|                     {% endfor %} | ||||
|                     <d:status>HTTP/1.1 404 Not Found</d:status> | ||||
|                 </d:propstat> | ||||
|             {% endif %} | ||||
|         </d:response> | ||||
|     {% endif %} | ||||
| </d:multistatus> | ||||
| @@ -0,0 +1,53 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" ?> | ||||
| <d:multistatus xmlns:d="DAV:"> | ||||
|     <d:response> | ||||
|         <d:href>{{ path('chill_docstore_dav_document_get', {'uuid': stored_object.uuid, 'access_token': access_token}) }}</d:href> | ||||
|         {% if properties.lastModified or properties.contentLength or properties.resourceType or properties.etag or properties.contentType or properties.creationDate %} | ||||
|             <d:propstat> | ||||
|                 <d:prop> | ||||
|                     {% if properties.resourceType %} | ||||
|                         <d:resourcetype/> | ||||
|                     {% endif %} | ||||
|                     {% if properties.creationDate %} | ||||
|                         <d:creationdate /> | ||||
|                     {% endif %} | ||||
|                     {% if properties.lastModified %} | ||||
|                         {%  if last_modified is not same as null %} | ||||
|                             <d:getlastmodified>{{  last_modified.format(constant('DATE_RSS')) }}</d:getlastmodified> | ||||
|                         {% else %} | ||||
|                             <d:getlastmodified /> | ||||
|                         {% endif %} | ||||
|                     {% endif %} | ||||
|                     {% if properties.contentLength %} | ||||
|                         {%  if content_length is not same as null %} | ||||
|                         <d:getcontentlength>{{ content_length }}</d:getcontentlength> | ||||
|                         {% else %} | ||||
|                         <d:getcontentlength /> | ||||
|                         {% endif %} | ||||
|                     {% endif %} | ||||
|                     {% if properties.etag %} | ||||
|                         {% if etag is not same as null %} | ||||
|                             <d:getetag>"{{ etag }}"</d:getetag> | ||||
|                         {% else %} | ||||
|                             <d:getetag /> | ||||
|                         {% endif %} | ||||
|                     {% endif %} | ||||
|                     {% if properties.contentType %} | ||||
|                         <d:getcontenttype>{{ stored_object.type }}</d:getcontenttype> | ||||
|                     {% endif %} | ||||
|                 </d:prop> | ||||
|                 <d:status>HTTP/1.1 200 OK</d:status> | ||||
|             </d:propstat> | ||||
|         {% endif %} | ||||
|         {% if properties.unknowns|length > 0 %} | ||||
|             <d:propstat> | ||||
|                 {% for k,u in properties.unknowns %} | ||||
|                     <d:prop {{ ('xmlns:ns' ~ k ~ '="' ~ u.xmlns|e('html_attr') ~ '"')|raw }}> | ||||
|                         <{{ 'ns'~ k ~ ':' ~ u.prop }} /> | ||||
|                     </d:prop> | ||||
|                 {% endfor %} | ||||
|                 <d:status>HTTP/1.1 404 Not Found</d:status> | ||||
|             </d:propstat> | ||||
|         {% endif %} | ||||
|     </d:response> | ||||
| </d:multistatus> | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user