Compare commits

..

1 Commits

Author SHA1 Message Date
ad5eae039c fix syntax error 2022-02-18 15:01:33 +01:00
254 changed files with 1950 additions and 6482 deletions

View File

@@ -29,7 +29,6 @@ variables:
REDIS_URL: redis://redis:6379
# change vendor dir to make the app install into tests/apps
COMPOSER_VENDOR_DIR: tests/app/vendor
DEFAULT_CARRIER_CODE: BE
stages:
- Composer install
@@ -79,7 +78,6 @@ psalm_tests:
image: registry.gitlab.com/chill-projet/chill-app/php-base-image:7.4
script:
- bin/grumphp run --tasks=psalm
allow_failure: true
artifacts:
expire_in: 30 min
paths:

View File

@@ -11,56 +11,9 @@ and this project adheres to
## Unreleased
<!-- write down unreleased development here -->
* [person] Add document generation in admin and in person/{id}/document (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/464)
* [activity] do not override location if already exist (when validating new activity) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/470)
* [parcours] Toggle emergency/intensity only by referrer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/442)
* [docstore] Add an API entrypoint for StoredObject (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466)
* [person] Add the possibility of uploading existing documents to AccPeriodWorkEvaluationDocument (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466)
* [person] Add title to AccPeriodWorkEvaluationDocument (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466)
* [person] Order social issues by the field "ordering" (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/388)
* [Person/Household list] when listing other simultaneous members of an household, exclude the members on person, not on members (avoid to show two membersship with the same person)
* [draft periods] add a delete button (if acl granted) on each draft period listed on draft period page (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/463)
* [Person] Display suffixText in RenderPerson, PersonText.vue, RenderPersonBox.vue (was made for displaying "enfant confie") (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/441)
* [person] residential address: show residential address or info in PersonRenderBox, refactor Residential Address (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/439)
* [thirdparty] Add a contact to a thirdparty from within onTheFly (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/345)
* [documents] Improve flex-table item-col placement when long buttons and long metadata
* [thirdparty] Fix display of multiple contact badges so they wrap onto next line (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/482)
* [confidential] Fix position of toggle button so it does not cover text nor fall outside of box (no issue)
* [parcours] Fix edit of both thirdparty and contact name (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/474)
* [template] do not list inactive templates (for doc generator)
* [thirdparty] Bugfix phonenumber -> telephone for thirdparty (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/487)
## Test releases
### test release 2022-02-21
* [notifications] Word 'un' changed to number '1' for notifications in user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/483)
* [documents] 'gabarit' changed to 'modèle' (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/405)
* [person_resources] Menu name and order changed (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/460)
* workflow: fix sending notifications
* [thirdparty] Extend the thirdparty search to thirdparty children (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/448)
* [person]: AddPersons: allow creation of person or thirdparty only (no users) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/422)
* [person]: AddPersons: allow creation of person or thirdparty depending on allowed types (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/422)
* [person]: AddPersons: add suggestion of name when creating new person or thirdparty (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/422)
* [main] Address: fix small bug: when modifying an address without street (isNoAddress), also check errors if street is an empty string as back-end change null value to empty string for street (and streetNumber)
* [main] Address: stronger client-side validation of addresses (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/449)
* [person] accompanying course: filter suggested entities by open participations (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/415)
[activity] can click through the cross icon for removing person in concerned group (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/476)
[activity] correct associated persons by considering only open participations (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/476)
* [person_resources]: Renderboxes used to display person/thirdparty info (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/465)
* [Household]: Add end date in HouseholdMember form for 'enfant hors menage' (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/434)
* [homepage_widget]: If no sender then display as 'notification automatique' (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/435)
* [parcours]: Order social activities and only display most recent three in parcours resumé (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/481)
* [3party]: 3party: redirect to parent when contact (child) is opened in view page
* [parcours / addresses]: launch an event when a person change address (either through changing household or because the household is associated to a new address). If the person is localising a course, the course location go back to a temporarily address.
* [thirdparty]: address/phonenumber/email/fonction displayed in thirdpartyrenderbox (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/401)
* [thirdparty_contact]: in search results the 'qualité' is displayed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/465)
* [bug]: fix confidential toggle of address in thirdpartyrenderbox (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/460)
## Test releases
* Creation of PickCivilityType, and implementation in PersonType and ThirdpartyType
### test release 2022-02-14
* AddPersons: remove ul-li html tags from AddPersons (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/419)
@@ -69,14 +22,13 @@ and this project adheres to
* [person] accompanying course work: fix on-the-fly update of thirdParty
* fix normalisation of accompanying course requestor api (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/378)
* [person] add a returnPath when clicking on some Person or ThirdParty badge (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/427)
* [person] accompanying course work: fix on-the-fly update of thirdParty
* [person] accompanying course work: fix on-the-fly update of thirdParty
* [on-the-fly] close modal only after validation
* [person] correct thirdparty PATCH url + add email and altnames in AddPerson and serializer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/433)
* change order for accompanying course work list
* [parcours]: Mes parcours brouillon added to user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/440)
* [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414)
* [person]: style fix in parcours listing per person. (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/432)
* [parcours]: Only the referrer can toggle the intensity of the parcours (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/442)
* [household]: display address of current household (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/415)
* ajoute un ordre dans les localisation (api)
* [pick entity]: fix translations in modal (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/419)
@@ -86,7 +38,7 @@ and this project adheres to
* [address]: Correction residential address 'depuis le' (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/459)
* [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414)
* [Thirdparty_contact]: address blurred if confidential in view page (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/450)
* [homepage_widget]: If no sender then display as 'notification automatique' (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/435)
### test release 2021-02-01
@@ -107,19 +59,7 @@ and this project adheres to
* [AddAddress] disable multiselect search, and rely only on most pertinent Cities and Street computed backend
* [fast_actions] improve fast-actions buttons override mechanism, fix https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/413
* [homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc.
* [thirdparty] Add a contact to a thirdparty from within onTheFly (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/345)
## Test releases
=======
* [homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc.
>>>>>>> issue422_and_others_on_AddPersons
=======
* [homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc.
* [thirdparty] Add a contact to a thirdparty from within onTheFly (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/345)
>>>>>>> b0d50d315c8e00959a967badac9cf5057ab2b4bc
### test release 2021-01-31
* [person] accompanying course: optimisation: do not fetch some resources for the banner (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/409)
@@ -325,7 +265,6 @@ and this project adheres to
* add an endpoint for checking permissions. See https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/232
* [activity] for a new activity: suggest and create on-the-fly locations based on the accompanying course location + location of the suggested parties
* [calendar] for a new rdv: suggest and create on-the-fly locations based on the accompanying course location + location of the suggested parties
* [period] Validation added when period is confidential and confirmed -> user cannot be null.
## Test releases

BIN
composer

Binary file not shown.

View File

@@ -22,7 +22,6 @@
"league/csv": "^9.7.1",
"nyholm/psr7": "^1.4",
"ocramius/package-versions": "^1.10",
"odolbeau/phone-number-bundle": "^3.6",
"phpoffice/phpspreadsheet": "^1.16",
"ramsey/uuid-doctrine": "^1.7",
"sensio/framework-extra-bundle": "^5.5",

View File

@@ -25,6 +25,11 @@ parameters:
count: 1
path: src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php
-
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Household\\\\MembersEditorFactory\\:\\:\\$validator\\.$#"
count: 2
path: src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php
-
message: "#^Variable variables are not allowed\\.$#"
count: 4

View File

@@ -295,6 +295,11 @@ parameters:
count: 3
path: src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php
-
message: "#^Only booleans are allowed in a negated boolean, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 2
@@ -320,6 +325,11 @@ parameters:
count: 1
path: src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Validation/Validator/ValidPhonenumber.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.18.0.0">
<files psalm-version="v4.15.0@a1b5e489e6fcebe40cb804793d964e99fc347820">
<file src="src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php">
<UndefinedClass occurrences="4">
<code>'ChillActivityBundle:ActivityReasonCategory'</code>
@@ -47,11 +47,6 @@
<code>Activity[]|array</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/AppKernel.php">
<DuplicateClass occurrences="1">
<code>AppKernel</code>
</DuplicateClass>
</file>
<file src="src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/autoload.php">
<MissingFile occurrences="1">
<code>require __DIR__ . '/../../../../../vendor/autoload.php'</code>
@@ -169,18 +164,72 @@
<code>type</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityReasonAggregatorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityTypeAggregatorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityUserAggregatorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Export/CountActivityTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Export/ListActivityTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Export/StatActivityDurationSumTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityReasonFilterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonHavingActivityBetweenDateFilterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="1">
<code>\Chill\PersonBundle\Export\Filter\PersonHavingActivityBetweenDateFilter</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityReasonTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
<TooFewArguments occurrences="2"/>
<UndefinedDocblockClass occurrences="1">
<code>Prophecy\Prophet</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityTypeTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillActivityBundle/Tests/Security/Authorization/ActivityVoterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="1">
<code>type</code>
</UndefinedDocblockClass>
@@ -205,6 +254,11 @@
<code>$asideActivityCategory</code>
</ParamNameMismatch>
</file>
<file src="src/Bundle/ChillAsideActivityBundle/src/Tests/Controller/AsideActivityControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php">
<InvalidStaticInvocation occurrences="3">
<code>$calculator::getAlias()</code>
@@ -234,6 +288,11 @@
<code>'ChillCalendarBundle:Calendar'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillCalendarBundle/Tests/Controller/CalendarControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Command/CreateFieldsOnGroupCommand.php">
<UndefinedClass occurrences="1">
<code>'ChillCustomFieldsBundle:CustomFieldsGroup'</code>
@@ -338,6 +397,10 @@
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsChoiceTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="4">
<code>type</code>
<code>type</code>
@@ -345,6 +408,61 @@
<code>type</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsNumberTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsTextTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextIntegerExtensionTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextNumberExtensionTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/Service/CustomFieldsHelperTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldsGroupRenderingTwigTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Encoder/DocGenEncoderTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/BaseContextDataTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php">
<UndefinedClass occurrences="1">
<code>'ChillDocStoreBundle:AccompanyingCourseDocument'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php">
<UndefinedClass occurrences="3">
<code>'ChillDocStoreBundle:DocumentCategory'</code>
@@ -352,6 +470,11 @@
<code>'ChillDocStoreBundle:DocumentCategory'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php">
<UndefinedClass occurrences="1">
<code>'ChillDocStoreBundle:PersonDocument'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillDocStoreBundle/Entity/Document.php">
<UndefinedDocblockClass occurrences="1">
<code>\Chill\PersonBundle\Entity\user</code>
@@ -447,6 +570,9 @@
<InvalidParamDefault occurrences="1">
<code>type</code>
</InvalidParamDefault>
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="8">
<code>'ChillEventBundle:Event'</code>
<code>'ChillEventBundle:Event'</code>
@@ -462,6 +588,10 @@
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillEventBundle/Tests/Search/EventSearchTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="1">
<code>'ChillMainBundle:Scope'</code>
</UndefinedClass>
@@ -761,6 +891,11 @@
<code>OptionsResolverInterface</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillMainBundle/Notification/Mailer.php">
<UndefinedDocblockClass occurrences="1">
<code>\Symfony\Component\Mailer\Exception\TransportExceptionInterface</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillMainBundle/Pagination/PageGenerator.php">
<UndefinedVariable occurrences="1">
<code>$current</code>
@@ -789,6 +924,11 @@
<code>$onlyEnabled</code>
</ParamNameMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/AppKernel.php">
<DuplicateClass occurrences="1">
<code>AppKernel</code>
</DuplicateClass>
</file>
<file src="src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/autoload.php">
<MissingFile occurrences="1">
<code>require __DIR__ . '/../../../../../vendor/autoload.php'</code>
@@ -916,15 +1056,158 @@
</UndefinedClass>
</file>
<file src="src/Bundle/ChillMainBundle/Test/Export/AbstractFilterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="1">
<code>type</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Controller/AddressControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php">
<MethodSignatureMismatch occurrences="2">
<code>protected function tearDown()</code>
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="40">
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>$this-&gt;prophet</code>
<code>Prophecy\Prophet</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Form/Type/PickCenterTypeTest.php">
<UndefinedClass occurrences="1">
<code>CenterType</code>
</UndefinedClass>
<UndefinedDocblockClass occurrences="1">
<code>CenterType</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Pagination/PageTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Pagination/PaginatorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Routing/Loader/RouteLoaderTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Search/AbstractSearchTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="1">
<code>unknown</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Security/PasswordRecover/TokenManagerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Security/Resolver/CenterResolverDispatcherTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DateNormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DoctrineExistingEntityNormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Services/MenuComposerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php">
<UndefinedDocblockClass occurrences="1">
<code>unknown</code>
@@ -1129,6 +1412,20 @@
<code>OptionsResolverInterface</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php">
<UndefinedClass occurrences="6">
<code>$qb</code>
<code>$qb</code>
<code>$qb</code>
<code>QueryBuilder</code>
<code>SocialAction</code>
<code>SocialAction</code>
</UndefinedClass>
<UndefinedVariable occurrences="2">
<code>$action</code>
<code>$orderBy</code>
</UndefinedVariable>
</file>
<file src="src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/AppKernel.php">
<DuplicateClass occurrences="1">
<code>AppKernel</code>
@@ -1208,13 +1505,33 @@
</ParamNameMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/AccompanyingPeriodConfidentialTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public static function setUpBeforeClass()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="2">
<code>AccompanyingPeriodRepository</code>
<code>stdClass</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public static function setUpBeforeClass()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php">
<InvalidThrow occurrences="1"/>
<MethodSignatureMismatch occurrences="3">
<code>public function setUp()</code>
<code>public function tearDown()</code>
<code>public static function setUpBeforeClass()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="3">
<code>'ChillMainBundle:Center'</code>
<code>'ChillPersonBundle:AccompanyingPeriod\ClosingMotive'</code>
@@ -1226,19 +1543,40 @@
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="1">
<code>User</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/PersonAddressControllerTest.php">
<InvalidScope occurrences="1">
<code>$this</code>
</InvalidScope>
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public static function setUpBeforeClass()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="1">
<code>'ChillPersonBundle:Person'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public static function tearDownAfterClass()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="2">
<code>'ChillMainBundle:Country'</code>
<code>'ChillPersonBundle:Person'</code>
@@ -1248,25 +1586,140 @@
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateWithHiddenFieldsTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="2">
<code>'ChillMainBundle:Country'</code>
<code>'ChillPersonBundle:Person'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="1">
<code>'ChillPersonBundle:Person'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewWithHiddenFieldsTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="1">
<code>'ChillPersonBundle:Person'</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Controller/SocialIssueApiControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php">
<AssignmentToVoid occurrences="1">
<code>$participationL</code>
</AssignmentToVoid>
<NullReference occurrences="1">
<code>getEndDate</code>
</NullReference>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/GenderAggregatorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregatorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Filter/AccompanyingPeriodFilterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Filter/BirthdayFilterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Export/Filter/GenderFilterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Form/Type/PickPersonTypeTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Security/Authorization/PersonVoterTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/AccompanyingPeriodWorkDocGenNormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonJsonNormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonValidationTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillPersonBundle/Timeline/AbstractTimelineAccompanyingPeriod.php">
<UndefinedClass occurrences="1">
@@ -1367,13 +1820,20 @@
<code>require __DIR__ . '/../../../../../vendor/autoload.php'</code>
</MissingFile>
</file>
<file src="src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerNextTest.php">
<MethodSignatureMismatch occurrences="1">
<code>public function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerTest.php">
<InvalidParamDefault occurrences="1">
<code>type</code>
</InvalidParamDefault>
<UndefinedDocblockClass occurrences="31">
<code>$client</code>
<code>$client</code>
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public static function setUpBeforeClass()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="29">
<code>$client</code>
<code>$client</code>
<code>$client</code>
@@ -1405,7 +1865,16 @@
<code>type</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillReportBundle/Tests/DependencyInjection/ChillReportExtensionTest.php">
<UndefinedClass occurrences="1">
<code>Exception</code>
</UndefinedClass>
</file>
<file src="src/Bundle/ChillReportBundle/Tests/Security/Authorization/ReportVoterTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public static function setUpBeforeClass()</code>
</MethodSignatureMismatch>
<UndefinedDocblockClass occurrences="3">
<code>type</code>
<code>type</code>
@@ -1413,6 +1882,10 @@
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php">
<MethodSignatureMismatch occurrences="2">
<code>public function setUp()</code>
<code>public function tearDown()</code>
</MethodSignatureMismatch>
<UndefinedClass occurrences="1">
<code>'ChillCustomFieldsBundle:CustomFieldsGroup'</code>
</UndefinedClass>
@@ -1485,6 +1958,11 @@
<code>CacheItempPoolInterface</code>
</UndefinedDocblockClass>
</file>
<file src="src/Bundle/ChillTaskBundle/Tests/Controller/SingleTaskControllerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php">
<UndefinedClass occurrences="1">
<code>$taggedService-&gt;getClass()::getKey()</code>
@@ -1510,6 +1988,11 @@
<code>$thirdParty</code>
</ParamNameMismatch>
</file>
<file src="src/Bundle/ChillThirdPartyBundle/Tests/Serializer/Normalizer/ThirdPartyJsonDenormalizerTest.php">
<MethodSignatureMismatch occurrences="1">
<code>protected function setUp()</code>
</MethodSignatureMismatch>
</file>
<file src="src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillDocumentManager.php">
<UndefinedDocblockClass occurrences="6">
<code>$object</code>

View File

@@ -357,7 +357,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
if (null !== $this->accompanyingPeriod) {
$personsAssociated = [];
foreach ($this->accompanyingPeriod->getOpenParticipations() as $participation) {
foreach ($this->accompanyingPeriod->getParticipations() as $participation) {
if ($this->persons->contains($participation->getPerson())) {
$personsAssociated[] = $participation->getPerson();
}

View File

@@ -1,7 +1,7 @@
<template>
<li>
<span :title="person.text" @click.prevent="$emit('remove', person)">
<span class="chill_denomination">
<span :title="person.text">
<span class="chill_denomination" @click.prevent="$emit('remove', person)">
<person-text :person="person" :isCut="true"></person-text>
</span>
</span>

View File

@@ -110,8 +110,10 @@ export default function prepareLocations(store) {
console.log('default loation id', window.default_location_id);
if (window.default_location_id) {
for (let group of store.state.availableLocations) {
console.log(group);
let location = group.locations.find((l) => l.id === window.default_location_id);
if (location !== undefined & store.state.activity.location === null) {
console.log(location);
if (location !== undefined) {
store.dispatch('updateLocation', location);
break;
}

View File

@@ -22,7 +22,7 @@ use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Chill\PersonBundle\Templating\Entity\PersonRender;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
@@ -43,7 +43,7 @@ class ActivityContext implements
private NormalizerInterface $normalizer;
private PersonRenderInterface $personRender;
private PersonRender $personRender;
private TranslatableStringHelperInterface $translatableStringHelper;
@@ -54,7 +54,7 @@ class ActivityContext implements
NormalizerInterface $normalizer,
TranslatableStringHelperInterface $translatableStringHelper,
EntityManagerInterface $em,
PersonRenderInterface $personRender,
PersonRender $personRender,
TranslatorInterface $translator,
BaseContextData $baseContextData
) {

View File

@@ -76,7 +76,7 @@ activity:
Insert a document: Insérer un document
Remove a document: Supprimer le document
comment: Commentaire
No documents: Aucun document
No documents: Pas de documents
#timeline
'%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"'

View File

@@ -207,21 +207,21 @@ final class DocGeneratorTemplateController extends AbstractController
$context instanceof DocGeneratorContextWithPublicFormInterface
&& $context->hasPublicForm($template, $entity) || $isTest
) {
if ($context instanceof DocGeneratorContextWithPublicFormInterface && $context->hasPublicForm($template, $entity)) {
if ($context instanceof DocGeneratorContextWithPublicFormInterface) {
$builder = $this->createFormBuilder(
array_merge(
$context->getFormData($template, $entity),
$isTest ? ['test_file' => null] : []
)
);
$context->buildPublicForm($builder, $template, $entity);
} else {
$builder = $this->createFormBuilder(
['test_file' => null]
);
}
$context->buildPublicForm($builder, $template, $entity);
if ($isTest) {
$builder->add('test_file', FileType::class, [
'label' => 'Template file',

View File

@@ -70,7 +70,6 @@ final class DocGeneratorTemplateRepository implements ObjectRepository
$builder
->where('t.entity LIKE :entity')
->andWhere($builder->expr()->eq('t.active', "'TRUE'"))
->setParameter('entity', addslashes($entity));
return $builder

View File

@@ -16,8 +16,8 @@
<div class="input-group mb-3">
<select class="form-select" v-model="template">
<option disabled selected value="">{{ $t('choose_a_template') }}</option>
<template v-for="t in templates" :key="t.id">
<option :value="t.id" >{{ t.name.fr || 'Aucun nom défini' }}</option>
<template v-for="t in templates">
<option v-bind:value="t.id">{{ t.name.fr || 'Aucun nom défini' }}</option>
</template>
</select>
<a v-if="canGenerate" class="btn btn-update btn-sm change-icon" :href="buildUrlGenerate" @click.prevent="clickGenerate($event, buildUrlGenerate)"><i class="fa fa-fw fa-cog"></i></a>

View File

@@ -2,11 +2,11 @@ docgen:
Generate a document: Génerer un document
Generate: Génerer
Document generation: Génération de documents
Manage templates and document generation: Gestion des documents générés et de leurs modèles
Manage templates and document generation: Gestion des documents générés et de leurs gabarits
Pick template context: Choisir un contexte
Context: Contexte
New template: Nouveau modèle
Edit template: Modifier modèle
New template: Nouveau gabarit
Edit template: Modifier gabarit
test generate: Tester la génération
With context: 'Avec le contexte :'

View File

@@ -21,8 +21,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod;
use DateTime;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -61,37 +59,21 @@ class DocumentAccompanyingCourseController extends AbstractController
}
/**
* @Route("/{id}/delete", name="chill_docstore_accompanying_course_document_delete")
* @Route("/{id}", name="accompanying_course_document_delete", methods="DELETE")
*/
public function delete(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
{
$this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::DELETE, $document);
$form = $this->createForm(FormType::class);
$form->add('submit', SubmitType::class, ['label' => 'Delete']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->remove($document);
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator->trans('The document is successfully removed'));
if ($request->query->has('returnPath')) {
return $this->redirect($request->query->get('returnPath'));
}
return $this->redirectToRoute('accompanying_course_document_index', ['course' => $course->getId()]);
if ($this->isCsrfTokenValid('delete' . $document->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$em->remove($document);
$em->flush();
}
return $this->render(
'ChillDocStoreBundle:AccompanyingCourseDocument:delete.html.twig',
[
'document' => $document,
'delete_form' => $form->createView(),
'accompanyingCourse' => $course,
]
return $this->redirectToRoute(
'accompanying_course_document_index',
['accompanyingCourse' => $course->getId()]
);
}

View File

@@ -14,7 +14,6 @@ namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\DocStoreBundle\Form\PersonDocumentType;
use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface;
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\Person;
@@ -23,8 +22,6 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter;
use DateTime;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -67,37 +64,22 @@ class DocumentPersonController extends AbstractController
}
/**
* @Route("/{id}/delete", name="chill_docstore_person_document_delete")
* @Route("/{id}", name="person_document_delete", methods="DELETE")
*/
public function delete(Request $request, Person $person, PersonDocument $document): Response
{
$this->denyAccessUnlessGranted(PersonDocumentVoter::DELETE, $document);
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_DELETE', $document);
$form = $this->createForm(FormType::class);
$form->add('submit', SubmitType::class, ['label' => 'Delete']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->remove($document);
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator->trans('The document is successfully removed'));
if ($request->query->has('returnPath')) {
return $this->redirect($request->query->get('returnPath'));
}
return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]);
if ($this->isCsrfTokenValid('delete' . $document->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();
$em->remove($document);
$em->flush();
}
return $this->render(
'ChillDocStoreBundle:PersonDocument:delete.html.twig',
[
'document' => $document,
'delete_form' => $form->createView(),
'person' => $person,
]
return $this->redirectToRoute(
'person_document_index',
['person' => $person->getId()]
);
}
@@ -116,6 +98,7 @@ class DocumentPersonController extends AbstractController
PersonDocumentType::class,
$document,
[
'center' => $document->getCenter(),
'role' => 'CHILL_PERSON_DOCUMENT_UPDATE',
]
);
@@ -216,6 +199,7 @@ class DocumentPersonController extends AbstractController
$document->setDate(new DateTime('Now'));
$form = $this->createForm(PersonDocumentType::class, $document, [
'center' => $document->getCenter(),
'role' => 'CHILL_PERSON_DOCUMENT_CREATE',
]);
$form->handleRequest($request);

View File

@@ -17,7 +17,6 @@ use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
@@ -47,28 +46,6 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf
$this->prependRoute($container);
$this->prependAuthorization($container);
$this->prependTwig($container);
$this->prependApis($container);
}
protected function prependApis(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'apis' => [
[
'class' => \Chill\DocStoreBundle\Entity\StoredObject::class,
'name' => 'stored_object',
'base_path' => '/api/1.0/docstore/stored-object',
'base_role' => 'ROLE_USER',
'actions' => [
'_entity' => [
'methods' => [
Request::METHOD_POST => true,
],
],
],
],
],
]);
}
protected function prependAuthorization(ContainerBuilder $container)

View File

@@ -34,19 +34,19 @@ class StoredObject implements AsyncFileInterface, Document
{
/**
* @ORM\Column(type="datetime", name="creation_date")
* @Serializer\Groups({"read", "write"})
* @Serializer\Groups({"read"})
*/
private DateTimeInterface $creationDate;
/**
* @ORM\Column(type="json", name="datas")
* @Serializer\Groups({"read", "write"})
* @Serializer\Groups({"read"})
*/
private array $datas = [];
/**
* @ORM\Column(type="text")
* @Serializer\Groups({"read", "write"})
* @Serializer\Groups({"read"})
*/
private $filename;
@@ -54,32 +54,30 @@ class StoredObject implements AsyncFileInterface, Document
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Serializer\Groups({"read", "write"})
* @Serializer\Groups({"read"})
*/
private $id;
/**
* @var int[]
* @ORM\Column(type="json", name="iv")
* @Serializer\Groups({"write"})
*/
private array $iv = [];
/**
* @ORM\Column(type="json", name="key")
* @Serializer\Groups({"write"})
*/
private array $keyInfos = [];
/**
* @ORM\Column(type="text", name="type")
* @Serializer\Groups({"read", "write"})
* @Serializer\Groups({"read"})
*/
private string $type = '';
/**
* @ORM\Column(type="uuid", unique=true)
* @Serializer\Groups({"read", "write"})
* @Serializer\Groups({"read"})
*/
private UuidInterface $uuid;

View File

@@ -13,13 +13,15 @@ namespace Chill\DocStoreBundle\Form;
use Chill\DocStoreBundle\Entity\Document;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\ChillTextareaType;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectManager;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\AbstractType;
@@ -29,16 +31,34 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class PersonDocumentType extends AbstractType
{
private CenterResolverDispatcher $centerResolverDispatcher;
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
* @var ObjectManager
*/
protected $om;
/**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* the user running this form.
*
* @var User
*/
protected $user;
private ParameterBagInterface $parameterBag;
private ScopeResolverDispatcher $scopeResolverDispatcher;
private TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
TranslatableStringHelperInterface $translatableStringHelper,
TranslatableStringHelper $translatableStringHelper,
ScopeResolverDispatcher $scopeResolverDispatcher,
ParameterBagInterface $parameterBag
) {
@@ -76,7 +96,7 @@ class PersonDocumentType extends AbstractType
if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) {
$builder->add('scope', ScopePickerType::class, [
'center' => $this->centerResolverDispatcher->resolveCenter($document),
'center' => $options['center'],
'role' => $options['role'],
]);
}
@@ -88,7 +108,8 @@ class PersonDocumentType extends AbstractType
'data_class' => Document::class,
]);
$resolver->setRequired(['role'])
->setAllowedTypes('role', ['string']);
$resolver->setRequired(['role', 'center'])
->setAllowedTypes('role', ['string'])
->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class]);
}
}

View File

@@ -4,12 +4,12 @@ var initializeDownload = require('./downloader.js');
/**
*
*
* define a dropzone for chill usage
*
* An event is launched when dropzone is initialize, allowing to customize events
*
* An event is launched when dropzone is initialize, allowing to customize events
* on dropzone :
*
*
* ```
* window.addEventListener("chill_dropzone_initialized", (e) => {
* // do something with dropzone:
@@ -18,7 +18,7 @@ var initializeDownload = require('./downloader.js');
* });
* });
* ```
*
*
*/
// load css
@@ -37,6 +37,7 @@ var keyDefinition = {
var searchForZones = function(root) {
var zones = root.querySelectorAll('div[data-stored-object]');
for(let i=0; i < zones.length; i++) {
initialize(zones[i]);
}
@@ -47,32 +48,32 @@ var getUploadUrl = function(zoneData, files) {
generateTempUrlPost = zoneData.zone.querySelector('input[data-async-file-upload]').dataset.generateTempUrlPost,
oReq = new XMLHttpRequest()
;
// arg, dropzone, you cannot handle async upload...
oReq.open("GET", generateTempUrlPost, false);
oReq.send();
if (oReq.readyState !== XMLHttpRequest.DONE) {
throw new Error("Error while fetching url to upload");
}
zoneData.params = JSON.parse(oReq.responseText);
return zoneData.params.url;
};
var encryptFile = function(originalFile, zoneData, done) {
var
var
iv = crypto.getRandomValues(new Uint8Array(16)),
reader = new FileReader(),
jsKey, rawKey
;
zoneData.originalType = originalFile.type;
reader.onload = e => {
window.crypto.subtle.generateKey(keyDefinition, true, [ "encrypt", "decrypt" ])
.then(key => {
.then(key => {
jsKey = key;
// we register the key somwhere
@@ -89,34 +90,34 @@ var encryptFile = function(originalFile, zoneData, done) {
rawKey: rawKey,
iv: iv
};
done(new File( [ encrypted ], zoneData.suffix));
});
};
reader.readAsArrayBuffer(originalFile);
};
var addBelowButton = (btn, zone, zoneData) => {
let
belowZone = zone.querySelector('.chill-dropzone__below-zone');
if (belowZone === null) {
belowZone = document.createElement('div');
belowZone.classList.add('chill-dropzone__below-zone');
zone.appendChild(belowZone);
}
belowZone.appendChild(btn);
};
var createZone = (zone, zoneData) => {
var
var
created = document.createElement('div'),
initMessage = document.createElement('div'),
initContent = zone.dataset.labelInitMessage,
dropzoneI;
created.classList.add('dropzone');
initMessage.classList.add('dz-message');
initMessage.appendChild(document.createTextNode(initContent));
@@ -141,7 +142,7 @@ var createZone = (zone, zoneData) => {
return zoneData.suffix;
}
});
dropzoneI.on("sending", function(file, xhr, formData) {
formData.append("redirect", zoneData.params.redirect);
formData.append("max_file_size", zoneData.params.max_file_size);
@@ -149,24 +150,24 @@ var createZone = (zone, zoneData) => {
formData.append("expires", zoneData.params.expires);
formData.append("signature", zoneData.params.signature);
});
dropzoneI.on("success", function(file, response) {
zoneData.currentFile = file;
storeDataInForm(zone, zoneData);
});
dropzoneI.on("addedfile", function(file) {
if (zoneData.hasOwnProperty('currentFile')) {
dropzoneI.removeFile(zoneData.currentFile);
}
});
dropzoneI.on("removedfile", function(file) {
removeDataInForm(zone, zoneData);
});
zone.insertBefore(created, zone.firstChild);
let event = new CustomEvent("chill_dropzone_initialized", {
detail: {
dropzone: dropzoneI,
@@ -178,7 +179,7 @@ var createZone = (zone, zoneData) => {
var initialize = function(zone) {
var
var
allowRemove = zone.dataset.allowRemove,
zoneData = { zone: zone, suffix: createFilename(), allowRemove: allowRemove, old: null }
;
@@ -203,13 +204,13 @@ var createFilename = () => {
};
var storeDataInForm = (zone, zoneData) => {
var
var
inputKey = zone.querySelector('input[data-stored-object-key]'),
inputIv = zone.querySelector('input[data-stored-object-iv]'),
inputObject = zone.querySelector('input[data-async-file-upload]'),
inputType = zone.querySelector('input[data-async-file-type]')
;
inputKey.value = JSON.stringify(zoneData.crypto.rawKey);
inputIv.value = JSON.stringify(Array.from(zoneData.crypto.iv));
inputType.value = zoneData.originalType;
@@ -219,18 +220,18 @@ var storeDataInForm = (zone, zoneData) => {
};
const restoreDataInForm = (zone, zoneData) => {
var
var
inputKey = zone.querySelector('input[data-stored-object-key]'),
inputIv = zone.querySelector('input[data-stored-object-iv]'),
inputObject = zone.querySelector('input[data-async-file-upload]'),
inputType = zone.querySelector('input[data-async-file-type]')
;
if (zoneData.old === null) {
console.log('should not have restored data');
return;
}
inputKey.value = zoneData.old.key;
inputIv.value = zoneData.old.iv;
inputType.value = zoneData.old.type;
@@ -240,21 +241,21 @@ const restoreDataInForm = (zone, zoneData) => {
};
const hasDataInForm = (zone, zoneData) => {
var
var
inputObject = zone.querySelector('input[data-async-file-upload]')
;
return inputObject.value.length > 0;
};
var removeDataInForm = (zone, zoneData) => {
var
var
inputKey = zone.querySelector('input[data-stored-object-key]'),
inputIv = zone.querySelector('input[data-stored-object-iv]'),
inputObject = zone.querySelector('input[data-async-file-upload]'),
inputType = zone.querySelector('input[data-async-file-type]')
;
// store data for future usage
zoneData.old = {
key: inputKey.value,
@@ -267,7 +268,7 @@ var removeDataInForm = (zone, zoneData) => {
inputIv.value = "";
inputType.value = "";
inputObject.value = "";
insertDownloadButton(zone);
};
@@ -278,25 +279,25 @@ var insertRemoveButton = (zone, zoneData) => {
labelRemove = zone.dataset.dictRemove,
labelCancel = 'Restaurer'
;
removeButton.classList.add('btn', 'btn-delete');
removeButton.textContent = labelRemove;
cancelButton.classList.add('btn', 'btn-cancel');
cancelButton.textContent = labelCancel;
removeButton.addEventListener('click', (e) => {
e.preventDefault();
if (zoneData.allowRemove === 'true') {
removeDataInForm(zone, zoneData);
cancelButton.addEventListener('click', (e) => {
e.preventDefault();
restoreDataInForm(zone, zoneData);
cancelButton.remove();
zone.querySelector('.dropzone').remove();
initialize(zone);
});
}
@@ -305,16 +306,16 @@ var insertRemoveButton = (zone, zoneData) => {
removeButton.remove();
createZone(zone, zoneData);
});
addBelowButton(removeButton, zone, zoneData);
// zone.appendChild(removeButton);
};
const removeDownloadButton = (zone, zoneData) => {
var
var
existingButtons = zone.querySelectorAll('a[data-download-button]')
;
// remove existing
existingButtons.forEach(function(b) {
b.remove();
@@ -322,7 +323,7 @@ const removeDownloadButton = (zone, zoneData) => {
};
var insertDownloadButton = (zone, zoneData) => {
var
var
existingButtons = zone.querySelectorAll('a[data-download-button]'),
newButton = document.createElement('a'),
inputKey = zone.querySelector('input[data-stored-object-key]'),
@@ -335,18 +336,18 @@ var insertDownloadButton = (zone, zoneData) => {
tempUrlGenerator = zone.dataset.tempUrlGenerator,
tempUrlGeneratorParams = new URLSearchParams()
;
// remove existing
existingButtons.forEach(function(b) {
b.remove();
});
if (inputObject.value === '') {
return;
}
tempUrlGeneratorParams.append('object_name', inputObject.value);
newButton.dataset.downloadButton = true;
newButton.dataset.key = inputKey.value;
newButton.dataset.iv = inputIv.value;
@@ -356,7 +357,7 @@ var insertDownloadButton = (zone, zoneData) => {
newButton.dataset.tempUrlGetGenerator = tempUrlGenerator + '?' + tempUrlGeneratorParams.toString();
newButton.classList.add('btn', 'btn-download', 'dz-bt-below-dropzone');
newButton.textContent = labelQuietButton;
addBelowButton(newButton, zone, zoneData);
//zone.appendChild(newButton);
initializeDownload(zone);
@@ -369,5 +370,3 @@ window.addEventListener('load', function(e) {
window.addEventListener('collection-add-entry', function(e) {
searchForZones(e.detail.entry);
});
export { searchForZones };

View File

@@ -1,157 +0,0 @@
<template>
<a class="btn btn-create" :title="$t(buttonTitle)" @click="openModal">
<span>{{ $t(buttonTitle) }}</span>
</a>
<teleport to="body">
<div>
<modal v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false">
<template v-slot:header>
{{ $t('upload_a_document') }}
</template>
<template v-slot:body>
<div id="dropZoneWrapper" ref="dropZoneWrapper">
<div
data-stored-object="data-stored-object"
:data-label-preparing="$t('data_label_preparing')"
:data-label-quiet-button="$t('data_label_quiet_button')"
:data-label-ready="$t('data_label_ready')"
:data-dict-file-too-big="$t('data_dict_file_too_big')"
:data-dict-default-message="$t('data_dict_default_message')"
:data-dict-remove-file="$t('data_dict_remove_file')"
:data-dict-max-files-exceeded="$t('data_dict_max_files_exceeded')"
:data-dict-cancel-upload="$t('data_dict_cancel_upload')"
:data-dict-cancel-upload-confirm="$t('data_dict_cancel_upload_confirm')"
:data-dict-upload-canceled="$t('data_dict_upload_canceled')"
:data-dict-remove="$t('data_dict_remove')"
:data-allow-remove="!options.required"
data-temp-url-generator="/asyncupload/temp_url/generate/GET">
<input
type="hidden"
data-async-file-upload="data-async-file-upload"
data-generate-temp-url-post="/asyncupload/temp_url/generate/post?expires_delay=180&amp;submit_delay=3600"
data-temp-url-get="/asyncupload/temp_url/generate/GET"
:data-max-files="options.maxFiles"
:data-max-post-size="options.maxPostSize"
:v-model="dataAsyncFileUpload"
>
<input
type="hidden"
data-stored-object-key="1"
>
<input
type="hidden"
data-stored-object-iv="1"
>
<input
type="hidden"
data-async-file-type="1"
>
</div>
</div>
</template>
<template v-slot:footer>
<button class="btn btn-create"
@click.prevent="saveDocument">
{{ $t('action.add')}}
</button>
</template>
</modal>
</div>
</teleport>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import { searchForZones } from '../../module/async_upload/uploader';
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
const i18n = {
messages: {
fr: {
upload_a_document: "Téléversez un document",
data_label_preparing: "Chargement...",
data_label_quiet_button: "Téléchargez le fichier existant",
data_label_ready: "Prêt à montrer",
data_dict_file_too_big: "Fichier trop volumineux",
data_dict_default_message: "Glissez votre fichier ou cliquez ici",
data_dict_remove_file: "Enlevez votre fichier pour en téléversez un autre",
data_dict_max_files_exceeded: "Nombre maximum de fichiers atteint. Enlevez les fichiers précédents",
data_dict_cancel_upload: "Annulez le téléversement",
data_dict_cancel_upload_confirm: "Êtes-vous sûr·e de vouloir annuler ce téléversement?",
data_dict_upload_canceled: "Téléversement annulé",
data_dict_remove: "Enlevez le fichier existant",
}
}
};
export default {
name: "AddAsyncUpload",
components: {
Modal
},
i18n,
props: [
'buttonTitle',
'options'
],
emits: ['addDocument'],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md"
},
}
},
updated() {
if (this.modal.showModal){
searchForZones(this.$refs.dropZoneWrapper);
}
},
methods: {
openModal() {
this.modal.showModal = true;
},
saveDocument() {
const dropzone = this.$refs.dropZoneWrapper;
if (dropzone) {
const inputKey = dropzone.querySelector('input[data-stored-object-key]');
const inputIv = dropzone.querySelector('input[data-stored-object-iv]');
const inputObject = dropzone.querySelector('input[data-async-file-upload]');
const inputType = dropzone.querySelector('input[data-async-file-type]');
const url = '/api/1.0/docstore/stored-object.json';
const body = {
filename: inputObject.value,
keyInfos: JSON.parse(inputKey.value),
iv: JSON.parse(inputIv.value),
type: inputType.value,
};
makeFetch('POST', url, body)
.then(r => {
this.$emit("addDocument", r);
this.modal.showModal = false;
})
.catch((error) => {
if (error.name === 'ValidationException') {
for (let v of error.violations) {
this.$toast.open({message: v });
}
} else {
console.error(error);
this.$toast.open({message: 'An error occurred'});
}
});
} else {
this.$toast.open({message: 'An error occurred - drop zone not found'});
}
}
}
}
</script>

View File

@@ -0,0 +1,5 @@
<form method="post" action="{{ path('accompanying_course_document_delete', {'id': document.id, 'course': course.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ document.id) }}">
<button class="btn btn-delete">{{ 'Delete' | trans }}</button>
</form>

View File

@@ -0,0 +1,19 @@
{% import '@ChillMain/Workflow/macro_breadcrumb.html.twig' as m %}
<div class="flex-grow-1 {% if add_classes is defined %}{{ add_classes }}{% else %}h2{% endif %}">
<div>
{% if concerne is defined and concerne == true %}
<span class="item-key">{{ 'Concerne'|trans }}: </span>
{% endif %}
{{ 'workflow.Document (n°%doc%)'|trans({'%doc%': document.id}) }}
{% if description is defined and description == true %}
{{ ' — ' ~ document.title }}
{% endif %}
</div>
{% if breadcrumb is defined and breadcrumb == true %}
{{ m.breadcrumb(_context) }}
{% endif %}
</div>

View File

@@ -1,43 +0,0 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'Delete document ?' }}{% endblock %}
{% block docdescription %}
<dl class="chill_view_data">
<dt>{{ 'Title'|trans }}</dt>
<dd>{{ document.title }}</dd>
{% if document.scope is not null %}
<dt>{{ 'Scope' | trans }}</dt>
<dd>{{ document.scope.name | localize_translatable_string }}</dd>
{% endif %}
<dt>{{ 'Category'|trans }}</dt>
<dd>{{ document.category.name|localize_translatable_string }}</dd>
<dt>{{ 'Description' | trans }}</dt>
<dd>
{% if document.description is empty %}
<span class="chill-no-data-statement">{{ 'Any description'|trans }}</span>
{% else %}
<blockquote class="chill-user-quote">
{{ document.description|chill_markdown_to_html }}
</blockquote>
{% endif %}
</dd>
</dl>
{% endblock %}
{% block content %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Delete document ?'|trans,
'display_content' : block('docdescription'),
'confirm_question' : 'Are you sure you want to remove this document ?'|trans,
'cancel_route' : 'accompanying_course_document_index',
'cancel_parameters' : {'course' : accompanyingCourse.id, 'id': document.id},
'form' : delete_form
} ) }}
{% endblock %}

View File

@@ -25,13 +25,8 @@
{{ 'Back to the list' | trans }}
</a>
</li>
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
<li class="edit">
<button class="btn btn-edit">{{ 'Edit'|trans }}</button>
<li class="edit">
<button class="btn btn-edit">{{ 'Edit'|trans }}</button>
</li>
</ul>

View File

@@ -10,18 +10,16 @@
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_docgen_picktemplate') }}
{{ encore_entry_script_tags('mod_entity_workflow_pick') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_docgen_picktemplate') }}
{{ encore_entry_link_tags('mod_entity_workflow_pick') }}
{% endblock %}
{% block content %}
<div class="document-list">
<div class="col-md-10 col-xxl">
<h1>{{ 'Documents' }}</h1>
{% if documents|length == 0 %}
@@ -29,7 +27,7 @@
{% else %}
<div class="flex-table chill-task-list">
{% for document in documents %}
{% include '@ChillDocStore/List/list_item.html.twig' %}
{% include 'ChillDocStoreBundle:List:list_item.html.twig' %}
{% endfor %}
</div>
{% endif %}

View File

@@ -49,17 +49,6 @@
{{ 'Back to the list' | trans }}
</a>
</li>
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('accompanying_course_document_edit', {'id': document.id, 'course': accompanyingCourse.id}) }}"
class="btn btn-edit" title="{{ 'Edit attributes' | trans }}"></a>
</li>
{% endif %}
<li>
{{ m.download_button(document.object, document.title) }}
</li>
@@ -68,6 +57,12 @@
{{ document.object|chill_document_edit_button }}
</li>
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('accompanying_course_document_edit', {'id': document.id, 'course': accompanyingCourse.id}) }}"
class="btn btn-edit" title="{{ 'Edit attributes' | trans }}"></a>
</li>
{% endif %}
{% set workflows_frame = chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) %}
{% if workflows_frame is not empty %}
<li>

View File

@@ -1,10 +1,8 @@
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
<div class="item-bloc">
<div class="item-row">
<div class="item-col" style="width: unset">
<div class="item-col">
<div class="denomination h2">
{{ document.title }}
</div>
@@ -24,68 +22,62 @@
<div class="item-col">
<div class="container">
{% if document.date is not null %}
<div class="dates row text-end">
<span>{{ document.date|format_date('short') }}</span>
<div class="dates row" style="float: right;">
<span>{{ document.createdAt|format_date('short') }}</span>
</div>
{% endif %}
</div>
</div>
</div>
{% if document.description is not empty %}
<div class="item-row">
<blockquote class="chill-user-quote col">
<div class="item-row separator">
<blockquote class="chill-user-quote">
{{ document.description|chill_markdown_to_html }}
</blockquote>
</div>
{% endif %}
<div class="item-row separator">
<div class="item-col item-meta">
{{ mmm.createdBy(document) }}
<div class="updatedBy">
{{ 'Created by'|trans }}:
<span class="user">{{ document.createdBy|chill_entity_render_string }}</span>
<span class="date">le {{ document.createdAt|format_date('long') }}</span>
</div>
</div>
<ul class="item-col record_actions flex-shrink-1">
{% if document.course is defined %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
<li>
{{ m.download_button(document.object, document.title) }}
</li>
<li>
<a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a>
</li>
{% endif %}
</div>
<div>
{% if document.course is defined %}
<ul class="record_actions">
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
<li>
{{ chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) }}
{{ m.download_button(document.object, document.title) }}
</li>
<li>
<a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a>
</li>
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
</li>
{% else %}
{% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
<li>
{{ m.download_button(document.object, document.title) }}
</li>
<li>
<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
</li>
{% endif %}
{% endif %}
</ul>
{% else %}
<ul class="record_actions">
{% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
<li>
{{ m.download_button(document.object, document.title) }}
</li>
<li>
<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
</li>
{% endif %}
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
<li>
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
</li>
{% endif %}
</ul>
{% endif %}
</div>
</div>

View File

@@ -1,43 +0,0 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}{{ 'Delete document ?' }}{% endblock %}
{% block docdescription %}
<dl class="chill_view_data">
<dt>{{ 'Title'|trans }}</dt>
<dd>{{ document.title }}</dd>
{% if document.scope is not null %}
<dt>{{ 'Scope' | trans }}</dt>
<dd>{{ document.scope.name | localize_translatable_string }}</dd>
{% endif %}
<dt>{{ 'Category'|trans }}</dt>
<dd>{{ document.category.name|localize_translatable_string }}</dd>
<dt>{{ 'Description' | trans }}</dt>
<dd>
{% if document.description is empty %}
<span class="chill-no-data-statement">{{ 'Any description'|trans }}</span>
{% else %}
<blockquote class="chill-user-quote">
{{ document.description|chill_markdown_to_html }}
</blockquote>
{% endif %}
</dd>
</dl>
{% endblock %}
{% block personcontent %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Delete document ?'|trans,
'display_content' : block('docdescription'),
'confirm_question' : 'Are you sure you want to remove this document ?'|trans,
'cancel_route' : 'person_document_index',
'cancel_parameters' : {'person' : person.id, 'id': document.id},
'form' : delete_form
} ) }}
{% endblock %}

View File

@@ -36,20 +36,20 @@
{{ form_row(form.description) }}
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
<ul class="record_actions sticky-form-buttons">
<ul class="record_actions">
<li class="cancel">
<a href="{{ chill_return_path_or('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
{{ 'Back to the list' | trans }}
</a>
</li>
{% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
</li>
{% endif %}
<li class="edit">
<button class="btn btn-edit">{{ 'Edit'|trans }}</button>
</li>
{# {% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
<li class="delete">
{{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }}
</li>
{% endif %} #}
</ul>
{{ form_end(form) }}

View File

@@ -26,17 +26,7 @@
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_docgen_picktemplate') }}
{{ encore_entry_script_tags('mod_entity_workflow_pick') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_docgen_picktemplate') }}
{{ encore_entry_link_tags('mod_entity_workflow_pick') }}
{% endblock %}
{% block personcontent %}
@@ -56,8 +46,6 @@
{{ chill_pagination(pagination) }}
<div data-docgen-template-picker="data-docgen-template-picker" data-entity-class="Chill\PersonBundle\Entity\Person" data-entity-id="{{ person.id }}"></div>
{% if is_granted('CHILL_PERSON_DOCUMENT_CREATE', person) %}
<ul class="record_actions sticky-form-buttons">
<li class="create">

View File

@@ -40,9 +40,9 @@
{{ form_row(form.description) }}
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
<ul class="record_actions sticky-form-buttons">
<ul class="record_actions">
<li class="cancel">
<a href="{{ chill_return_path_or('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
{{ 'Back to the list' | trans }}
</a>
</li>

View File

@@ -64,9 +64,13 @@
</a>
</li>
{% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
<li class="delete">
<a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
<li>
{{ m.download_button(document.object, document.title) }}
</li>
{% if chill_document_is_editable(document.object) %}
<li>
{{ document.object|chill_document_edit_button }}
</li>
{% endif %}
@@ -78,15 +82,5 @@
</li>
{% endif %}
<li>
{{ m.download_button(document.object, document.title) }}
</li>
{% if chill_document_is_editable(document.object) %}
<li>
{{ document.object|chill_document_edit_button }}
</li>
{% endif %}
{# {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} #}
{# {{ include('ChillDocStoreBundle:PersonDocument:_delete_form.html.twig') }} #}
{% endblock %}

View File

@@ -1,55 +0,0 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\DocStoreBundle\Serializer\Normalizer;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\StoredObjectRepository;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
use function array_key_exists;
use function is_array;
class StoredObjectDenormalizer implements DenormalizerInterface
{
use ObjectToPopulateTrait;
private StoredObjectRepository $storedObjectRepository;
public function __construct(StoredObjectRepository $storedObjectRepository)
{
$this->storedObjectRepository = $storedObjectRepository;
}
public function denormalize($data, $type, $format = null, array $context = [])
{
$object = $this->extractObjectToPopulate(StoredObject::class, $context);
if (null !== $object) {
return $object;
}
return $this->storedObjectRepository->find($data['id']);
}
public function supportsDenormalization($data, $type, $format = null)
{
if (false === is_array($data)) {
return false;
}
if (false === array_key_exists('id', $data)) {
return false;
}
return StoredObject::class === $type;
}
}

View File

@@ -15,12 +15,11 @@ use ChampsLibres\WopiLib\Contract\Service\Discovery\DiscoveryInterface;
use Chill\DocStoreBundle\Entity\StoredObject;
use Twig\Environment;
use Twig\Extension\RuntimeExtensionInterface;
use function array_key_exists;
final class WopiEditTwigExtensionRuntime implements RuntimeExtensionInterface
class WopiEditTwigExtensionRuntime implements RuntimeExtensionInterface
{
private const TEMPLATE = '@ChillDocStore/Button/wopi_edit_document.html.twig';
public const TEMPLATE = '@ChillDocStore/Button/wopi_edit_document.html.twig';
private DiscoveryInterface $discovery;
@@ -33,6 +32,10 @@ final class WopiEditTwigExtensionRuntime implements RuntimeExtensionInterface
{
$mime_type = $this->discovery->discoverMimeType($document->getType());
if ([] === $mime_type) {
return false;
}
foreach ($mime_type as $item) {
if (array_key_exists('default', $item) && 'true' === $item['default']) {
return true;

View File

@@ -14,51 +14,19 @@ namespace Chill\DocStoreBundle\Workflow;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Symfony\Contracts\Translation\TranslatorInterface;
class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowHandlerInterface
{
private EntityRepository $repository;
private TranslatorInterface $translator;
/**
* TODO: injecter le repository directement.
*/
public function __construct(
EntityManagerInterface $em,
TranslatorInterface $translator
) {
public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository(AccompanyingCourseDocument::class);
$this->translator = $translator;
}
public function getEntityData(EntityWorkflow $entityWorkflow, array $options = []): array
{
$course = $this->getRelatedEntity($entityWorkflow)
->getCourse();
$persons = [];
if (null !== $course) {
$persons = $course->getCurrentParticipations()->map(static function (AccompanyingPeriodParticipation $participation) {
return $participation->getPerson();
})->toArray();
}
return [
'persons' => array_values($persons),
];
}
public function getEntityTitle(EntityWorkflow $entityWorkflow, array $options = []): string
{
$doc = $this->getRelatedEntity($entityWorkflow);
return $this->translator->trans('workflow.Document (n°%doc%)', ['%doc%' => $entityWorkflow->getRelatedEntityId()])
. ' - ' . $doc->getTitle();
}
public function getRelatedEntity(EntityWorkflow $entityWorkflow): ?AccompanyingCourseDocument
@@ -84,6 +52,16 @@ class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowHandler
];
}
public function getTemplateTitle(EntityWorkflow $entityWorkflow, array $options = []): string
{
return '@ChillDocStore/AccompanyingCourseDocument/_workflow.title.html.twig';
}
public function getTemplateTitleData(EntityWorkflow $entityWorkflow, array $options = []): array
{
return $this->getTemplateData($entityWorkflow, $options);
}
public function supports(EntityWorkflow $entityWorkflow, array $options = []): bool
{
return $entityWorkflow->getRelatedEntityClass() === AccompanyingCourseDocument::class;

View File

@@ -1,46 +0,0 @@
---
openapi: "3.0.0"
info:
version: "1.0.0"
title: "Chill api"
description: "Api documentation for chill. Currently, work in progress"
servers:
- url: "/api"
description: "Your current dev server"
components:
schemas:
StoredObject:
type: object
properties:
id:
type: integer
filename:
type: string
type:
type: string
paths:
/1.0/docstore/stored-object.json:
post:
tags:
- storedobject
summary: Create a stored object
requestBody:
description: "A stored object"
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/StoredObject"
responses:
200:
description: "OK"
content:
application/json:
schema:
$ref: "#/components/schemas/StoredObject"
403:
description: "Unauthorized"
422:
description: "Invalid data"

View File

@@ -1,7 +1,4 @@
module.exports = function(encore)
{
encore.addAliases({
ChillDocStoreAssets: __dirname + '/Resources/public'
});
encore.addEntry('mod_async_upload', __dirname + '/Resources/public/module/async_upload/index.js');
};

View File

@@ -33,10 +33,3 @@ services:
resource: './../Workflow/'
autoconfigure: true
autowire: true
Chill\DocStoreBundle\Serializer\Normalizer\:
autowire: true
resource: '../Serializer/Normalizer/'
tags:
- { name: 'serializer.normalizer', priority: 16 }

View File

@@ -19,12 +19,6 @@ The document is successfully registered: Le document est enregistré
The document is successfully updated: Le document est mis à jour
Any description: Aucune description
# delete
Delete document ?: Supprimer le document ?
Are you sure you want to remove this document ?: Êtes-vous sûr·e de vouloir supprimer ce document ?
The document is successfully removed: Le document a été supprimé
# dropzone upload
File too big: Fichier trop volumineux
Drop your file or click here: Cliquez ici ou faites glissez votre nouveau fichier dans cette zone

View File

@@ -29,6 +29,7 @@ use Chill\MainBundle\Security\ProvideRoleInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
use Chill\MainBundle\Templating\Entity\CompilerPass as RenderEntityCompilerPass;
use Chill\MainBundle\Templating\UI\NotificationCounterInterface;
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -69,6 +70,7 @@ class ChillMainBundle extends Bundle
$container->addCompilerPass(new MenuCompilerPass());
$container->addCompilerPass(new ACLFlagsCompilerPass());
$container->addCompilerPass(new GroupingCenterCompilerPass());
$container->addCompilerPass(new RenderEntityCompilerPass());
$container->addCompilerPass(new CRUDControllerCompilerPass());
}
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class CivilityApiController extends ApiController
{
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
{
return $query->addOrderBy('e.order', 'ASC');
}
}

View File

@@ -11,12 +11,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -26,71 +21,17 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\SerializerInterface;
class WorkflowApiController
{
private EntityManagerInterface $entityManager;
private EntityWorkflowRepository $entityWorkflowRepository;
private PaginatorFactory $paginatorFactory;
private Security $security;
private SerializerInterface $serializer;
public function __construct(
EntityManagerInterface $entityManager,
EntityWorkflowRepository $entityWorkflowRepository,
PaginatorFactory $paginatorFactory,
Security $security,
SerializerInterface $serializer
) {
$this->entityManager = $entityManager;
$this->entityWorkflowRepository = $entityWorkflowRepository;
$this->paginatorFactory = $paginatorFactory;
$this->security = $security;
$this->serializer = $serializer;
}
/**
* Return a list of workflow which are waiting an action for the user.
*
* @Route("/api/1.0/main/workflow/my", methods={"GET"})
*/
public function myWorkflow(Request $request): JsonResponse
public function __construct(Security $security, EntityManagerInterface $entityManager)
{
if (!$this->security->isGranted('ROLE_USER') || !$this->security->getUser() instanceof User) {
throw new AccessDeniedException();
}
$total = $this->entityWorkflowRepository->countByDest($this->security->getUser());
if ($request->query->getBoolean('countOnly', false)) {
return new JsonResponse(
$this->serializer->serialize(new Counter($total), 'json'),
JsonResponse::HTTP_OK,
[],
true
);
}
$paginator = $this->paginatorFactory->create($total);
$workflows = $this->entityWorkflowRepository->findByDest(
$this->security->getUser(),
['id' => 'DESC'],
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
return new JsonResponse(
$this->serializer->serialize(new Collection($workflows, $paginator), 'json', ['groups' => ['read']]),
JsonResponse::HTTP_OK,
[],
true
);
$this->entityManager = $entityManager;
$this->security = $security;
}
/**

View File

@@ -11,26 +11,21 @@ declare(strict_types=1);
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowComment;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep;
use Chill\MainBundle\Form\EntityWorkflowCommentType;
use Chill\MainBundle\Form\WorkflowStepType;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Security\Authorization\EntityWorkflowVoter;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Chill\MainBundle\Workflow\Validator\StepDestValid;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\TransitionBlocker;
@@ -85,9 +80,7 @@ class WorkflowController extends AbstractController
$entityWorkflow
->setRelatedEntityClass($request->query->get('entityClass'))
->setRelatedEntityId($request->query->getInt('entityId'))
->setWorkflowName($request->query->get('workflow'))
->addSubscriberToStep($this->getUser())
->addSubscriberToFinal($this->getUser());
->setWorkflowName($request->query->get('workflow'));
$errors = $this->validator->validate($entityWorkflow, null, ['creation']);
@@ -111,121 +104,6 @@ class WorkflowController extends AbstractController
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
}
/**
* @Route("/{_locale}/main/workflow/{id}/delete", name="chill_main_workflow_delete")
*/
public function delete(EntityWorkflow $entityWorkflow, Request $request): Response
{
$this->denyAccessUnlessGranted(EntityWorkflowVoter::DELETE, $entityWorkflow);
$form = $this->createForm(FormType::class);
$form->add('submit', SubmitType::class, ['label' => 'workflow.Delete workflow']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->remove($entityWorkflow);
$this->entityManager->flush();
$this->addFlash('success', $this->translator->trans('workflow.Workflow deleted with success'));
return $this->redirectToRoute('chill_main_homepage');
}
return $this->render('@ChillMain/Workflow/delete.html.twig', [
'entityWorkflow' => $entityWorkflow,
'delete_form' => $form->createView(),
'handler' => $this->entityWorkflowManager->getHandler($entityWorkflow),
]);
}
/**
* @Route("/{_locale}/main/workflow-step/{id}/access_key", name="chill_main_workflow_grant_access_by_key")
*/
public function getAccessByAccessKey(EntityWorkflowStep $entityWorkflowStep, Request $request): Response
{
if (null === $accessKey = $request->query->get('accessKey', null)) {
throw new BadRequestException('accessKey is missing');
}
if (!$this->getUser() instanceof User) {
throw new AccessDeniedException('Not a valid user');
}
if ($entityWorkflowStep->getAccessKey() !== $accessKey) {
throw new AccessDeniedException('Access key is invalid');
}
if (!$entityWorkflowStep->isWaitingForTransition()) {
$this->addFlash('error', $this->translator->trans('workflow.Steps is not waiting for transition. Maybe someone apply the transition before you ?'));
} else {
$entityWorkflowStep->addDestUserByAccessKey($this->getUser());
$this->entityManager->flush();
$this->addFlash('success', $this->translator->trans('workflow.You get access to this step'));
}
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflowStep->getEntityWorkflow()->getId()]);
}
/**
* Previous workflows where the user has applyed a transition.
*
* @Route("/{_locale}/main/workflow/list/previous_transitionned", name="chill_main_workflow_list_previous_transitionned")
*/
public function myPreviousWorkflowsTransitionned(Request $request): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
$total = $this->entityWorkflowRepository->countByPreviousTransitionned($this->getUser());
$paginator = $this->paginatorFactory->create($total);
$workflows = $this->entityWorkflowRepository->findByPreviousTransitionned(
$this->getUser(),
['createdAt' => 'DESC'],
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
return $this->render(
'@ChillMain/Workflow/list.html.twig',
[
'help' => 'workflow.Previous workflow transitionned help',
'workflows' => $this->buildHandler($workflows),
'paginator' => $paginator,
'step' => 'previous_transitionned',
]
);
}
/**
* Previous workflows where the user was mentioned, but did not give any reaction.
*
* @Route("/{_locale}/main/workflow/list/previous_without_reaction", name="chill_main_workflow_list_previous_without_reaction")
*/
public function myPreviousWorkflowsWithoutReaction(Request $request): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
$total = $this->entityWorkflowRepository->countByPreviousDestWithoutReaction($this->getUser());
$paginator = $this->paginatorFactory->create($total);
$workflows = $this->entityWorkflowRepository->findByPreviousDestWithoutReaction(
$this->getUser(),
['createdAt' => 'DESC'],
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
return $this->render(
'@ChillMain/Workflow/list.html.twig',
[
'help' => 'workflow.Previous workflow without reaction help',
'workflows' => $this->buildHandler($workflows),
'paginator' => $paginator,
'step' => 'previous_without_reaction',
]
);
}
/**
* @Route("/{_locale}/main/workflow/list/dest", name="chill_main_workflow_list_dest")
*/
@@ -319,22 +197,24 @@ class WorkflowController extends AbstractController
);
}
$entityWorkflow->futureDestUsers = $transitionForm['future_dest_users']->getData();
$entityWorkflow->futureDestEmails = $transitionForm['future_dest_emails']->getData();
$workflow->apply($entityWorkflow, $transition);
foreach ($transitionForm['future_dest_users']->getData() as $user) {
$entityWorkflow->getCurrentStep()->addDestUser($user);
}
foreach ($transitionForm['future_dest_emails']->getData() as $email) {
$entityWorkflow->getCurrentStep()->addDestEmail($email);
$errors = $this->validator->validate(
$entityWorkflow->getCurrentStep(),
new StepDestValid()
);
if (count($errors) === 0) {
$this->entityManager->flush();
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
}
$this->entityManager->flush();
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);
return new Response((string) $errors, Response::HTTP_UNPROCESSABLE_ENTITY);
}
if ($transitionForm->isSubmitted() && !$transitionForm->isValid()) {
@@ -361,8 +241,8 @@ class WorkflowController extends AbstractController
return $this->render(
'@ChillMain/Workflow/index.html.twig',
[
'handler' => $handler,
'handler_template' => $handler->getTemplate($entityWorkflow),
'handler_template_title' => $handler->getTemplateTitle($entityWorkflow),
'handler_template_data' => $handler->getTemplateData($entityWorkflow),
'transition_form' => isset($transitionForm) ? $transitionForm->createView() : null,
'entity_workflow' => $entityWorkflow,

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection;
use Chill\MainBundle\Controller\AddressApiController;
use Chill\MainBundle\Controller\CivilityApiController;
use Chill\MainBundle\Controller\LocationController;
use Chill\MainBundle\Controller\LocationTypeController;
use Chill\MainBundle\Controller\UserController;
@@ -39,7 +38,6 @@ use Chill\MainBundle\Form\LocationTypeType;
use Chill\MainBundle\Form\UserJobType;
use Chill\MainBundle\Form\UserType;
use Exception;
use Misd\PhoneNumberBundle\Doctrine\DBAL\Types\PhoneNumberType;
use Ramsey\Uuid\Doctrine\UuidType;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -236,7 +234,6 @@ class ChillMainExtension extends Extension implements
'dateinterval' => NativeDateIntervalType::class,
'point' => PointType::class,
'uuid' => UuidType::class,
'phone_number' => PhoneNumberType::class,
],
],
]
@@ -562,21 +559,6 @@ class ChillMainExtension extends Extension implements
],
],
],
[
'class' => \Chill\MainBundle\Entity\Civility::class,
'name' => 'civility',
'base_path' => '/api/1.0/main/civility',
'base_role' => 'ROLE_USER',
'controller' => CivilityApiController::class,
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
],
],
],
],
],
]);
}

View File

@@ -97,9 +97,6 @@ class Configuration implements ConfigurationInterface
->scalarNode('twilio_secret')
->defaultNull()
->end()
->scalarNode('default_carrier_code')
->defaultNull()
->end()
->end()
->end()
->arrayNode('acl')

View File

@@ -139,10 +139,12 @@ class Address
private $point;
/**
* @var PostalCode
*
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
* @Groups({"write"})
*/
private ?PostalCode $postcode = null;
private $postcode;
/**
* @var string|null
@@ -304,8 +306,10 @@ class Address
/**
* Get postcode.
*
* @return PostalCode
*/
public function getPostcode(): ?PostalCode
public function getPostcode()
{
return $this->postcode;
}

View File

@@ -17,7 +17,6 @@ use Symfony\Component\Serializer\Annotation as Serializer;
/**
* @ORM\Table(name="chill_main_civility")
* @ORM\Entity
* @Serializer\DiscriminatorMap(typeProperty="type", mapping={"chill_main_civility": Civility::class})
*/
class Civility
{
@@ -30,7 +29,6 @@ class Civility
/**
* @ORM\Column(type="boolean")
* @Serializer\Groups({"read"})
*/
private bool $active = true;

View File

@@ -18,9 +18,9 @@ use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
use DateTimeImmutable;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
use libphonenumber\PhoneNumber;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Table(name="chill_main_location")
@@ -90,18 +90,20 @@ class Location implements TrackCreationInterface, TrackUpdateInterface
private ?string $name = null;
/**
* @ORM\Column(type="phone_number", nullable=true)
* @ORM\Column(type="string", length=64, nullable=true)
* @Serializer\Groups({"read", "write", "docgen:read"})
* @Assert\Regex(pattern="/^([\+{1}])([0-9\s*]{4,20})$/")
* @PhonenumberConstraint(type="any")
*/
private ?PhoneNumber $phonenumber1 = null;
private ?string $phonenumber1 = null;
/**
* @ORM\Column(type="phone_number", nullable=true)
* @ORM\Column(type="string", length=64, nullable=true)
* @Serializer\Groups({"read", "write", "docgen:read"})
* @Assert\Regex(pattern="/^([\+{1}])([0-9\s*]{4,20})$/")
* @PhonenumberConstraint(type="any")
*/
private ?PhoneNumber $phonenumber2 = null;
private ?string $phonenumber2 = null;
/**
* @ORM\Column(type="datetime_immutable", nullable=true)
@@ -160,12 +162,12 @@ class Location implements TrackCreationInterface, TrackUpdateInterface
return $this->name;
}
public function getPhonenumber1(): ?PhoneNumber
public function getPhonenumber1(): ?string
{
return $this->phonenumber1;
}
public function getPhonenumber2(): ?PhoneNumber
public function getPhonenumber2(): ?string
{
return $this->phonenumber2;
}
@@ -236,14 +238,14 @@ class Location implements TrackCreationInterface, TrackUpdateInterface
return $this;
}
public function setPhonenumber1(?PhoneNumber $phonenumber1): self
public function setPhonenumber1(?string $phonenumber1): self
{
$this->phonenumber1 = $phonenumber1;
return $this;
}
public function setPhonenumber2(?PhoneNumber $phonenumber2): self
public function setPhonenumber2(?string $phonenumber2): self
{
$this->phonenumber2 = $phonenumber2;

View File

@@ -9,28 +9,24 @@
declare(strict_types=1);
namespace Chill\PersonBundle\Entity\Person;
namespace Chill\MainBundle\Entity;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Repository\ResidentialAddressRepository;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\ResidentialAddressRepository;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ORM\Entity(repositoryClass=ResidentialAddressRepository::class)
* @ORM\Table(name="chill_person_residential_address")
* @ORM\Table(name="chill_main_residential_address")
*/
class ResidentialAddress
{
/**
* @ORM\ManyToOne(targetEntity=Address::class)
* @ORM\JoinColumn(nullable=true)
* @Groups({"read"})
*/
private ?Address $address = null;
@@ -41,22 +37,18 @@ class ResidentialAddress
/**
* @ORM\Column(type="datetime_immutable", nullable=true)
* @Groups({"read"})
*/
private ?DateTimeImmutable $endDate = null;
/**
* @ORM\ManyToOne(targetEntity=Person::class)
* @ORM\JoinColumn(nullable=true)
* @Groups({"read"})
* @Context(normalizationContext={"groups": {"minimal"}})
*/
private ?Person $hostPerson = null;
/**
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
* @ORM\JoinColumn(nullable=true)
* @Groups({"read"})
*/
private ?ThirdParty $hostThirdParty = null;
@@ -75,7 +67,6 @@ class ResidentialAddress
/**
* @ORM\Column(type="datetime_immutable")
* @Groups({"read"})
*/
private ?DateTimeImmutable $startDate = null;

View File

@@ -41,28 +41,6 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
use TrackUpdateTrait;
/**
* a list of future dest emails for the next steps.
*
* This is in used in order to let controller inform who will be the future emails which will validate
* the next step. This is necessary to perform some computation about the next emails, before they are
* associated to the entity EntityWorkflowStep.
*
* @var array|string[]
*/
public array $futureDestEmails = [];
/**
* a list of future dest users for the next steps.
*
* This is in used in order to let controller inform who will be the future users which will validate
* the next step. This is necessary to perform some computation about the next users, before they are
* associated to the entity EntityWorkflowStep.
*
* @var array|User[]
*/
public array $futureDestUsers = [];
/**
* @ORM\OneToMany(targetEntity=EntityWorkflowComment::class, mappedBy="entityWorkflow", orphanRemoval=true)
*

View File

@@ -27,11 +27,6 @@ use function in_array;
*/
class EntityWorkflowStep
{
/**
* @ORM\Column(type="text", nullable=false)
*/
private string $accessKey;
/**
* @ORM\Column(type="text", options={"default": ""})
*/
@@ -53,12 +48,6 @@ class EntityWorkflowStep
*/
private Collection $destUser;
/**
* @ORM\ManyToMany(targetEntity=User::class)
* @ORM\JoinTable(name="chill_main_workflow_entity_step_user_by_accesskey")
*/
private Collection $destUserByAccessKey;
/**
* @ORM\ManyToOne(targetEntity=EntityWorkflow::class, inversedBy="steps")
*/
@@ -97,7 +86,7 @@ class EntityWorkflowStep
private ?string $transitionAfter = null;
/**
* @ORM\Column(type="datetime_immutable", nullable=true, options={"default": null})
* @ORM\Column(type="datetime_immutable")
*/
private ?DateTimeImmutable $transitionAt = null;
@@ -115,8 +104,6 @@ class EntityWorkflowStep
public function __construct()
{
$this->destUser = new ArrayCollection();
$this->destUserByAccessKey = new ArrayCollection();
$this->accessKey = bin2hex(openssl_random_pseudo_bytes(32));
}
public function addDestEmail(string $email): self
@@ -132,45 +119,11 @@ class EntityWorkflowStep
{
if (!$this->destUser->contains($user)) {
$this->destUser[] = $user;
$this->getEntityWorkflow()
->addSubscriberToFinal($user)
->addSubscriberToStep($user);
}
return $this;
}
public function addDestUserByAccessKey(User $user): self
{
if (!$this->destUserByAccessKey->contains($user) && !$this->destUser->contains($user)) {
$this->destUserByAccessKey[] = $user;
$this->getEntityWorkflow()
->addSubscriberToFinal($user)
->addSubscriberToStep($user);
}
return $this;
}
public function getAccessKey(): string
{
return $this->accessKey;
}
/**
* get all the users which are allowed to apply a transition: those added manually, and
* those added automatically bu using an access key.
*/
public function getAllDestUser(): Collection
{
return new ArrayCollection(
[
...$this->getDestUser()->toArray(),
...$this->getDestUserByAccessKey()->toArray(),
]
);
}
public function getComment(): string
{
return $this->comment;
@@ -187,21 +140,13 @@ class EntityWorkflowStep
}
/**
* get dest users added by the creator.
*
* You should **not** rely on this method to get all users which are able to
* apply a transition on this step. Use @see{EntityWorkflowStep::getAllDestUser} instead.
* @return ArrayCollection|Collection
*/
public function getDestUser(): collection
public function getDestUser()
{
return $this->destUser;
}
public function getDestUserByAccessKey(): Collection
{
return $this->destUserByAccessKey;
}
public function getEntityWorkflow(): ?EntityWorkflow
{
return $this->entityWorkflow;
@@ -252,19 +197,6 @@ class EntityWorkflowStep
return $this->freezeAfter;
}
public function isWaitingForTransition(): bool
{
if (null !== $this->transitionAfter) {
return false;
}
if ($this->isFinal()) {
return false;
}
return true;
}
public function removeDestEmail(string $email): self
{
$this->destEmail = array_filter($this->destEmail, static function (string $existing) use ($email) {
@@ -281,13 +213,6 @@ class EntityWorkflowStep
return $this;
}
public function removeDestUserByAccessKey(User $user): self
{
$this->destUserByAccessKey->removeElement($user);
return $this;
}
public function setComment(?string $comment): EntityWorkflowStep
{
$this->comment = (string) $comment;

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Form;
use Chill\MainBundle\Entity\LocationType as EntityLocationType;
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
use Chill\MainBundle\Form\Type\PickAddressType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
@@ -47,8 +46,8 @@ final class LocationFormType extends AbstractType
},
])
->add('name', TextType::class)
->add('phonenumber1', ChillPhoneNumberType::class, ['required' => false])
->add('phonenumber2', ChillPhoneNumberType::class, ['required' => false])
->add('phonenumber1', TextType::class, ['required' => false])
->add('phonenumber2', TextType::class, ['required' => false])
->add('email', TextType::class, ['required' => false])
->add('address', PickAddressType::class, [
'required' => false,

View File

@@ -1,61 +0,0 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Form\Type;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberUtil;
use Misd\PhoneNumberBundle\Form\Type\PhoneNumberType;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use function array_key_exists;
class ChillPhoneNumberType extends AbstractType
{
private string $defaultCarrierCode;
private PhoneNumberUtil $phoneNumberUtil;
public function __construct(ParameterBagInterface $parameterBag)
{
$this->defaultCarrierCode = $parameterBag->get('chill_main')['phone_helper']['default_carrier_code'];
$this->phoneNumberUtil = PhoneNumberUtil::getInstance();
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefault('default_region', $this->defaultCarrierCode)
->setDefault('format', PhoneNumberFormat::NATIONAL)
->setDefault('type', \libphonenumber\PhoneNumberType::FIXED_LINE_OR_MOBILE)
->setNormalizer('attr', function (Options $options, $value) {
if (array_key_exists('placeholder', $value)) {
return $value;
}
$examplePhoneNumber = $this->phoneNumberUtil->getExampleNumberForType($this->defaultCarrierCode, $options['type']);
return array_merge(
$value,
[
'placeholder' => PhoneNumberUtil::getInstance()->format($examplePhoneNumber, $options['format']),
]
);
});
}
public function getParent()
{
return PhoneNumberType::class;
}
}

View File

@@ -38,7 +38,7 @@ class ObjectToIdTransformer implements DataTransformerInterface
*/
public function reverseTransform($id)
{
if (null === $id) {
if (!$id) {
return null;
}
@@ -46,7 +46,7 @@ class ObjectToIdTransformer implements DataTransformerInterface
->getRepository($this->class)
->find($id);
if (null === $object) {
if (!$object) {
throw new TransformationFailedException();
}
@@ -62,7 +62,7 @@ class ObjectToIdTransformer implements DataTransformerInterface
*/
public function transform($object)
{
if (null === $object) {
if (!$object) {
return '';
}

View File

@@ -1,57 +0,0 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Form\Type;
use Chill\MainBundle\Entity\Civility;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class PickCivilityType extends AbstractType
{
private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefault('label', 'Civility')
->setDefault(
'choice_label',
function (Civility $civility): string {
return $this->translatableStringHelper->localize($civility->getName());
}
)
->setDefault(
'query_builder',
static function (EntityRepository $er): QueryBuilder {
return $er->createQueryBuilder('c')
->where('c.active = true')
->orderBy('c.order');
},
)
->setDefault('placeholder', 'choose civility')
->setDefault('class', Civility::class);
}
public function getParent()
{
return EntityType::class;
}
}

View File

@@ -9,11 +9,9 @@
declare(strict_types=1);
namespace Chill\PersonBundle\Form;
namespace Chill\MainBundle\Form\Type;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\MainBundle\Form\Type\PickAddressType;
use Chill\PersonBundle\Entity\Person\ResidentialAddress;
use Chill\MainBundle\Entity\ResidentialAddress;
use Chill\PersonBundle\Form\Type\PickPersonDynamicType;
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
use Symfony\Component\Form\AbstractType;

View File

@@ -13,7 +13,6 @@ namespace Chill\MainBundle\Form;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep;
use Chill\MainBundle\Form\Type\ChillCollectionType;
use Chill\MainBundle\Form\Type\ChillTextareaType;
use Chill\MainBundle\Form\Type\PickUserDynamicType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
@@ -22,14 +21,8 @@ use LogicException;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Transition;
use function array_key_exists;
@@ -153,22 +146,6 @@ class WorkflowStepType extends AbstractType
'label' => 'workflow.dest for next steps',
'multiple' => true,
'mapped' => false,
])
->add('future_dest_emails', ChillCollectionType::class, [
'label' => 'workflow.dest by email',
'help' => 'workflow.dest by email help',
'mapped' => false,
'allow_add' => true,
'entry_type' => EmailType::class,
'button_add_label' => 'workflow.Add an email',
'button_remove_label' => 'workflow.Remove an email',
'empty_collection_explain' => 'workflow.Any email',
'entry_options' => [
'constraints' => [
new NotNull(), new NotBlank(), new Email(['checkMX' => true]),
],
'label' => 'Email',
],
]);
}
@@ -198,37 +175,6 @@ class WorkflowStepType extends AbstractType
->setRequired('transition')
->setAllowedTypes('transition', 'bool')
->setRequired('entity_workflow')
->setAllowedTypes('entity_workflow', EntityWorkflow::class)
->setDefault('constraints', [
new Callback(
function ($step, ExecutionContextInterface $context, $payload) {
/** @var EntityWorkflowStep $step */
$form = $context->getObject();
$workflow = $this->registry->get($step->getEntityWorkflow(), $step->getEntityWorkflow()->getWorkflowName());
$transition = $form['transition']->getData();
$toFinal = true;
foreach ($transition->getTos() as $to) {
$meta = $workflow->getMetadataStore()->getPlaceMetadata($to);
if (
!array_key_exists('isFinal', $meta) || false === $meta['isFinal']
) {
$toFinal = false;
}
}
$destUsers = $form['future_dest_users']->getData();
$destEmails = $form['future_dest_emails']->getData();
if (!$toFinal && [] === $destUsers && [] === $destEmails) {
$context
->buildViolation('workflow.You must add at least one dest user or email')
->atPath('future_dest_users')
->addViolation();
}
}
),
]);
->setAllowedTypes('entity_workflow', EntityWorkflow::class);
}
}

View File

@@ -1,54 +0,0 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Phonenumber;
use libphonenumber\PhoneNumber;
/**
* Helper to some task linked to phonenumber.
*
* Currently, only Twilio is supported (https://www.twilio.com/lookup). A method
* allow to check if the helper is configured for validation. This should be used
* before doing some validation.
*/
interface PhoneNumberHelperInterface
{
public function format(PhoneNumber $phoneNumber): string;
/**
* Get type (mobile, landline, ...) for phone number.
*/
public function getType(string $phonenumber): string;
/**
* Return true if the validation is configured and available.
*/
public function isPhonenumberValidationConfigured(): bool;
/**
* Return true if the phonenumber is a landline or voip phone. Return always true
* if the validation is not configured.
*/
public function isValidPhonenumberAny(string $phonenumber): bool;
/**
* Return true if the phonenumber is a landline or voip phone. Return always true
* if the validation is not configured.
*/
public function isValidPhonenumberLandOrVoip(string $phonenumber): bool;
/**
* REturn true if the phoennumber is a mobile phone. Return always true
* if the validation is not configured.
*/
public function isValidPhonenumberMobile(string $phonenumber): bool;
}

View File

@@ -15,12 +15,8 @@ use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\ServerException;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberUtil;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use function array_key_exists;
use function in_array;
@@ -28,32 +24,40 @@ use function json_decode;
use function preg_replace;
use function strlen;
final class PhonenumberHelper implements PhoneNumberHelperInterface
/**
* Helper to some task linked to phonenumber.
*
* Currently, only Twilio is supported (https://www.twilio.com/lookup). A method
* allow to check if the helper is configured for validation. This should be used
* before doing some validation.
*/
class PhonenumberHelper
{
public const FORMAT_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s';
public const LOOKUP_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s';
private CacheItemPoolInterface $cachePool;
protected CacheItemPoolInterface $cachePool;
private array $config;
/**
* TRUE if the client is properly configured.
*/
protected bool $isConfigured = false;
private bool $isConfigured = false;
protected LoggerInterface $logger;
private LoggerInterface $logger;
private PhonenumberUtil $phoneNumberUtil;
private Client $twilioClient;
/**
* Twilio client.
*/
protected Client $twilioClient;
public function __construct(
CacheItemPoolInterface $cacheUserData,
ParameterBagInterface $parameterBag,
CacheItemPoolInterface $cachePool,
$config,
LoggerInterface $logger
) {
$this->logger = $logger;
$this->cachePool = $cacheUserData;
$this->config = $config = $parameterBag->get('chill_main.phone_helper');
$this->cachePool = $cachePool;
if (
array_key_exists('twilio_sid', $config)
@@ -68,19 +72,11 @@ final class PhonenumberHelper implements PhoneNumberHelperInterface
]);
$this->isConfigured = true;
}
$this->phoneNumberUtil = PhoneNumberUtil::getInstance();
}
/**
* @param string $phoneNumber A national phone number starting with +
*
* @throws NumberParseException
*/
public function format(PhoneNumber $phoneNumber): string
public function format($phonenumber)
{
return $this->phoneNumberUtil
->formatOutOfCountryCallingNumber($phoneNumber, $this->config['default_carrier_code']);
return $this->performTwilioFormat($phonenumber);
}
/**
@@ -141,7 +137,7 @@ final class PhonenumberHelper implements PhoneNumberHelperInterface
}
/**
* REturn true if the phonenumber is a mobile phone. Return always true
* REturn true if the phoennumber is a mobile phone. Return always true
* if the validation is not configured.
*
* @param string $phonenumber
@@ -161,7 +157,68 @@ final class PhonenumberHelper implements PhoneNumberHelperInterface
return 'mobile' === $validation;
}
private function performTwilioLookup($phonenumber)
protected function performTwilioFormat($phonenumber)
{
if (false === $this->isPhonenumberValidationConfigured()) {
return $phonenumber;
}
// filter only number
$filtered = preg_replace('/[^0-9]/', '', $phonenumber);
$item = $this->cachePool->getItem('pnum_format_nat_' . $filtered);
if ($item->isHit()) {
return $item->get();
}
try {
$response = $this->twilioClient->get(sprintf(self::FORMAT_URI, '+' . $filtered), [
'http_errors' => true,
]);
} catch (ClientException $e) {
$response = $e->getResponse();
$this->logger->error('[phonenumber helper] Could not format number '
. 'due to client error', [
'message' => $response->getBody()->getContents(),
'status_code' => $response->getStatusCode(),
'phonenumber' => $phonenumber,
]);
return $phonenumber;
} catch (ServerException $e) {
$response = $e->getResponse();
$this->logger->error('[phonenumber helper] Could not format number '
. 'due to server error', [
'message' => $response->getBody()->getContents(),
'status_code' => $response->getStatusCode(),
'phonenumber' => $phonenumber,
]);
return null;
} catch (ConnectException $e) {
$this->logger->error('[phonenumber helper] Could not format number '
. 'due to connect error', [
'message' => $e->getMessage(),
'phonenumber' => $phonenumber,
]);
return null;
}
$format = json_decode($response->getBody()->getContents())->national_format;
$item
->set($format)
// expires after 3d
->expiresAfter(3600 * 24 * 3);
$this->cachePool->save($item);
return $format;
}
protected function performTwilioLookup($phonenumber)
{
if (false === $this->isPhonenumberValidationConfigured()) {
return null;
@@ -173,7 +230,7 @@ final class PhonenumberHelper implements PhoneNumberHelperInterface
$item = $this->cachePool->getItem('pnum_' . $filtered);
if ($item->isHit()) {
return $item->get();
//return $item->get();
}
try {

View File

@@ -16,7 +16,10 @@ use Twig\TwigFilter;
class Templating extends AbstractExtension
{
protected PhonenumberHelper $phonenumberHelper;
/**
* @var PhonenumberHelper
*/
protected $phonenumberHelper;
public function __construct(PhonenumberHelper $phonenumberHelper)
{

View File

@@ -9,14 +9,10 @@
declare(strict_types=1);
namespace Chill\PersonBundle\Repository;
namespace Chill\MainBundle\Repository;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Person\ResidentialAddress;
use DateTimeImmutable;
use Chill\MainBundle\Entity\ResidentialAddress;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
/**
@@ -32,39 +28,6 @@ class ResidentialAddressRepository extends ServiceEntityRepository
parent::__construct($registry, ResidentialAddress::class);
}
public function buildQueryFindCurrentResidentialAddresses(Person $person, ?DateTimeImmutable $at = null): QueryBuilder
{
$date = null === $at ? new DateTimeImmutable('today') : $at;
$qb = $this->createQueryBuilder('ra');
$dateFilter = $qb->expr()->andX(
$qb->expr()->lte('ra.startDate', ':dateIn'),
$qb->expr()->orX(
$qb->expr()->isNull('ra.endDate'),
$qb->expr()->gte('ra.endDate', ':dateIn')
)
);
$qb
->where($dateFilter)
->setParameter('dateIn', $date, Types::DATE_IMMUTABLE)
->andWhere('ra.person = :person')
->setParameter('person', $person);
return $qb;
}
/**
* @return array|ResidentialAddress[]|null
*/
public function findCurrentResidentialAddressByPerson(Person $person, ?DateTimeImmutable $at = null): array
{
return $this->buildQueryFindCurrentResidentialAddresses($person, $at)
->select('ra')
->getQuery()
->getResult();
}
// /**
// * @return ResidentialAddress[] Returns an array of ResidentialAddress objects
// */

View File

@@ -34,20 +34,6 @@ class EntityWorkflowRepository implements ObjectRepository
return (int) $qb->getQuery()->getSingleScalarResult();
}
public function countByPreviousDestWithoutReaction(User $user): int
{
$qb = $this->buildQueryByPreviousDestWithoutReaction($user)->select('count(ew)');
return (int) $qb->getQuery()->getSingleScalarResult();
}
public function countByPreviousTransitionned(User $user): int
{
$qb = $this->buildQueryByPreviousTransitionned($user)->select('count(ew)');
return (int) $qb->getQuery()->getSingleScalarResult();
}
public function countBySubscriber(User $user): int
{
$qb = $this->buildQueryBySubscriber($user)->select('count(ew)');
@@ -92,32 +78,6 @@ class EntityWorkflowRepository implements ObjectRepository
return $qb->getQuery()->getResult();
}
public function findByPreviousDestWithoutReaction(User $user, ?array $orderBy = null, $limit = null, $offset = null): array
{
$qb = $this->buildQueryByPreviousDestWithoutReaction($user)->select('ew');
foreach ($orderBy as $key => $sort) {
$qb->addOrderBy('ew.' . $key, $sort);
}
$qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery()->getResult();
}
public function findByPreviousTransitionned(User $user, ?array $orderBy = null, $limit = null, $offset = null): array
{
$qb = $this->buildQueryByPreviousTransitionned($user)->select('ew')->distinct(true);
foreach ($orderBy as $key => $sort) {
$qb->addOrderBy('ew.' . $key, $sort);
}
$qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery()->getResult();
}
public function findBySubscriber(User $user, ?array $orderBy = null, $limit = null, $offset = null): array
{
$qb = $this->buildQueryBySubscriber($user)->select('ew');
@@ -160,41 +120,6 @@ class EntityWorkflowRepository implements ObjectRepository
return $qb;
}
private function buildQueryByPreviousDestWithoutReaction(User $user): QueryBuilder
{
$qb = $this->repository->createQueryBuilder('ew');
$qb->join('ew.steps', 'step');
$qb->where(
$qb->expr()->andX(
$qb->expr()->isMemberOf(':user', 'step.destUser'),
$qb->expr()->neq('step.transitionBy', ':user'),
)
);
$qb->setParameter('user', $user);
return $qb;
}
private function buildQueryByPreviousTransitionned(User $user): QueryBuilder
{
$qb = $this->repository->createQueryBuilder('ew');
$qb->join('ew.steps', 'step');
$qb->where(
$qb->expr()->andX(
$qb->expr()->eq('step.transitionBy', ':user'),
)
);
$qb->setParameter('user', $user);
return $qb;
}
private function buildQueryBySubscriber(User $user): QueryBuilder
{
$qb = $this->repository->createQueryBuilder('ew');

View File

@@ -278,7 +278,6 @@ table.table-bordered {
}
/// meta-data
div.createdBy,
div.updatedBy,
div.metadata {
span.user, span.date {

View File

@@ -279,7 +279,6 @@ div.wrap-header {
li {
margin-right: 5px;
margin-bottom: 5px;
}
}
}
@@ -317,7 +316,7 @@ div.float-button {
div.action {
height: calc(100% - 0em);
shape-outside: inset(calc(100% - 2em) 0 0);
shape-outside: inset(calc(100% - 4em) 0 0);
display: flex;
align-items: flex-end;
padding: 0 0 0 1em;
@@ -329,10 +328,6 @@ div.float-button {
padding: 0;
}
}
.chill-entity.entity-address .address p {
display: unset;
}
}
&.debug {
padding: 1em;

View File

@@ -1,7 +1,7 @@
ul.record_actions {
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex-wrap: wrap-reverse;
justify-content: flex-end;
padding: 0.5em 0;

View File

@@ -73,8 +73,8 @@ section.chill-entity {
}
p {
display: inline-block;
//margin: 0 0 0 1.5em;
//text-indent: -1.5em;
margin: 0 0 0 1.5em;
text-indent: -1.5em;
&.street {
span.streetnumber {

View File

@@ -1,7 +1,7 @@
/**
* Generic api method that can be adapted to any fetch request
*/
const makeFetch = (method, url, body) => {
const makeFetch = (method, url, body) => {
return fetch(url, {
method: method,
headers: {
@@ -11,20 +11,19 @@ const makeFetch = (method, url, body) => {
})
.then(response => {
if (response.ok) {
console.log('200 error')
return response.json();
}
if (response.status === 422) {
console.log('422 error')
return response.json().then(response => {
throw ValidationException(response)
});
}
if (response.status === 403) {
console.log('403 error')
throw AccessException(response);
return response.json().then(() => {
throw AccessException();
});
}
throw {
@@ -89,13 +88,14 @@ const ValidationException = (response) => {
error.violations = response.violations.map((violation) => `${violation.title}: ${violation.propertyPath}`);
error.titles = response.violations.map((violation) => violation.title);
error.propertyPaths = response.violations.map((violation) => violation.propertyPath);
return error;
}
const AccessException = (response) => {
const AccessException = () => {
const error = {};
error.name = 'AccessException';
error.violations = ['You are not allowed to perform this action'];
error.violations = ['You are no longer permitted to perform this action'];
return error;
}

View File

@@ -50,7 +50,7 @@ var handleAdd = function(button) {
empty_explain = collection.querySelector('li[data-collection-empty-explain]'),
entry = document.createElement('li'),
event = new CustomEvent('collection-add-entry', { detail: { collection: collection, entry: entry } }),
counter = collection.childNodes.length + parseInt(Math.random() * 1000000)
counter = collection.childNodes.length,
content
;
content = prototype.replace(new RegExp('__name__', 'g'), counter);

View File

@@ -1,39 +1,11 @@
.confidential {
.confidential{
display: flex;
position: relative;
}
.toggle-far-twig {
i {
bottom: 0px;
right: -30px;
}
}
.toggle-close-twig {
i {
bottom: 0px;
right: -5px;
}
}
.toggle{
margin-left: 30px;
margin-top: 5px;
cursor: pointer;
position: absolute;
z-index: 5;
right: -30px
}
.toggle-far {
bottom: 0px;
right: 20px !important;
}
.toggle-close {
bottom: 125px;
right: 15px !important;
}
.blur {
-webkit-filter: blur(5px);
-moz-filter: blur(5px);

View File

@@ -3,7 +3,7 @@ import {ShowHide} from 'ChillMainAssets/lib/show_hide/show_hide.js';
window.addEventListener('DOMContentLoaded', function() {
let
divTransitions = document.querySelector('#transitions'),
futureDestUsersContainer = document.querySelector('#futureDests')
futureDestUsersContainer = document.querySelector('#futureDestUsers')
;
if (null !== divTransitions) {
@@ -67,4 +67,24 @@ window.addEventListener('DOMContentLoaded', function() {
});
}
// validate form
let form = document.querySelector('form[name="workflow_step"]');
if (form === null) {
console.error('form to validate not found');
}
form.addEventListener('submit', function (event) {
const datas = new FormData(event.target);
if (datas.has('workflow_step[future_dest_users]')) {
const dests = JSON.parse(datas.get('workflow_step[future_dest_users]'));
if (dests === null || (dests instanceof Array && dests.length === 0)) {
event.preventDefault();
console.log('no users!');
window.alert('Indiquez un utilisateur pour traiter la prochaine étape.');
}
}
});
});

View File

@@ -260,7 +260,8 @@ export default {
editPane: false,
datePane: false,
loading: false,
success: false
success: false,
dirty: false
},
errors: [],
defaultz: {
@@ -536,19 +537,17 @@ export default {
checkErrors() {
this.errors = [];
if (this.entity.selected.country === null) {
this.errors.push("Un pays doit être sélectionné.");
}
if (this.entity.selected.city === null) {
this.errors.push("Une ville doit être sélectionnée.");
} else {
if (this.flag.dirty) {
if (this.entity.selected.country === null) {
this.errors.push("Un pays doit être sélectionné.");
}
if (Object.keys(this.entity.selected.city).length === 0) {
this.errors.push("Une ville doit être sélectionnée.");
}
}
if (!this.entity.selected.isNoAddress) {
if (this.entity.selected.address.street === null || this.entity.selected.address.street === '' || this.entity.selected.address.streetNumber === null || this.entity.selected.address.streetNumber === '') {
this.errors.push("Une adresse doit être sélectionnée.");
if (!this.entity.selected.isNoAddress) {
if (this.entity.selected.address.street === null || this.entity.selected.address.streetNumber === null) {
this.errors.push("Une adresse doit être sélectionnée.");
}
}
}
},
@@ -568,7 +567,7 @@ export default {
this.entity.selected.country = this.context.edit ? this.entity.address.country : {};
this.entity.selected.postcode = this.context.edit ? this.entity.address.postcode : {};
this.entity.selected.city = this.context.edit ? this.entity.address.postcode : {};
this.entity.selected.city = {};
this.entity.selected.address = {};
this.entity.selected.address.street = this.context.edit ? this.entity.address.street: null;
@@ -584,8 +583,6 @@ export default {
this.entity.selected.writeNew.address = this.context.edit && this.entity.address.addressReference === null && this.entity.address.street.length > 0
this.entity.selected.writeNew.postcode = false // NB: this used to be this.context.edit, but think it was erroneous;
console.log('!! just set writeNew.postcode to', this.entity.selected.writeNew.postcode);
this.checkErrors();
},
/*

View File

@@ -111,9 +111,11 @@ export default {
this.entity.selected.address.streetNumber = value.streetNumber;
this.entity.selected.writeNew.address = false;
this.updateMapCenter(value.point);
this.flag.dirty = true;
this.checkErrors();
},
remove() {
this.flag.dirty = true;
this.entity.selected.address = {};
this.checkErrors();
},
@@ -156,6 +158,7 @@ export default {
this.entity.selected.address.street = addr.street;
this.entity.selected.address.streetNumber = addr.number;
this.entity.selected.writeNew.address = true;
this.flag.dirty = true;
this.checkErrors();
}
},

View File

@@ -125,9 +125,11 @@ export default {
if (value.center) {
this.updateMapCenter(value.center);
}
this.flag.dirty = true;
this.checkErrors();
},
remove() {
this.flag.dirty = true;
this.entity.selected.city = {};
this.checkErrors();
},

View File

@@ -51,6 +51,7 @@ export default {
init() {
if (this.value !== undefined) {
this.selectCountry(this.value);
this.flag.dirty = false;
}
},
selectCountryByCode(countryCode) {
@@ -66,6 +67,7 @@ export default {
this.checkErrors();
},
remove() {
this.flag.dirty = true;
this.entity.selected.country = null;
this.checkErrors();
},

View File

@@ -157,7 +157,6 @@ export default {
set(value) {
console.log('isNoAddress value', value);
this.entity.selected.isNoAddress = value;
this.checkErrors();
},
get() {
return this.entity.selected.isNoAddress;

View File

@@ -1,7 +1,7 @@
<template>
<h2>{{ $t('main_title') }}</h2>
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link"
@@ -23,6 +23,7 @@
:class="{'active': activeTab === 'MyAccompanyingCourses'}"
@click="selectTab('MyAccompanyingCourses')">
{{ $t('my_accompanying_courses.tab') }}
<tab-counter :count="state.accompanyingCourses.count"></tab-counter>
</a>
</li>
<li class="nav-item">
@@ -50,19 +51,11 @@
<tab-counter :count="state.tasks.alert.count"></tab-counter>
</a>
</li>
<li class="nav-item">
<a class="nav-link"
:class="{'active': activeTab === 'MyWorkflows'}"
@click="selectTab('MyWorkflows')">
{{ $t('my_workflows.tab') }}
<tab-counter :count="state.workflows.count"></tab-counter>
</a>
</li>
<li class="nav-item loading ms-auto py-2" v-if="loading">
<i class="fa fa-circle-o-notch fa-spin fa-lg text-chill-gray" :title="$t('loading')"></i>
</li>
</ul>
<div class="my-4">
<my-customs
v-if="activeTab === 'MyCustoms'">
@@ -82,9 +75,6 @@
<my-notifications
v-else-if="activeTab === 'MyNotifications'">
</my-notifications>
<my-workflows
v-else-if="activeTab === 'MyWorkflows'">
</my-workflows>
</div>
</template>
@@ -95,7 +85,6 @@ import MyEvaluations from './MyEvaluations';
import MyTasks from './MyTasks';
import MyAccompanyingCourses from './MyAccompanyingCourses';
import MyNotifications from './MyNotifications';
import MyWorkflows from './MyWorkflows.vue';
import TabCounter from './TabCounter';
import { mapState } from "vuex";
@@ -106,7 +95,6 @@ export default {
MyWorks,
MyEvaluations,
MyTasks,
MyWorkflows,
MyAccompanyingCourses,
MyNotifications,
TabCounter,
@@ -138,7 +126,6 @@ export default {
'MyWorks',
'MyEvaluations',
'MyTasks',
'MyWorkflows',
]) {
this.$store.dispatch('getByTab', { tab: m, param: "countOnly=1" });
}

View File

@@ -66,8 +66,6 @@ export default {
return appMessages.fr.the_activity;
case 'Chill\\PersonBundle\\Entity\\AccompanyingPeriod':
return appMessages.fr.the_course;
case 'Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow':
return appMessages.fr.the_workflow;
default:
throw 'notification type unknown';
}
@@ -78,8 +76,6 @@ export default {
return `/fr/activity/${n.relatedEntityId}/show`
case 'Chill\\PersonBundle\\Entity\\AccompanyingPeriod':
return `/fr/parcours/${n.relatedEntityId}`
case 'Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow':
return `/fr/main/workflow/${n.relatedEntityId}/show`
default:
throw 'notification type unknown';
}

View File

@@ -1,88 +0,0 @@
<template>
<div class="alert alert-light">{{ $t('my_workflows.description') }}</div>
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span>
<tab-table v-else>
<template v-slot:thead>
<th scope="col">{{ $t('Object_workflow') }}</th>
<th scope="col">{{ $t('Step') }}</th>
<th scope="col">{{ $t('concerned_users') }}</th>
<th scope="col"></th>
</template>
<template v-slot:tbody>
<tr v-for="(w, i) in workflows.results" :key="`workflow-${i}`">
<td>{{ w.title }}</td>
<td>
<div class="workflow">
<div class="breadcrumb">
<i class="fa fa-circle me-1 text-chill-yellow mx-2"></i>
<span class="mx-2">{{ getStep(w) }}</span>
</div>
</div>
</td>
<td v-if="w.datas.persons !== null">
<span v-for="p in w.datas.persons" class="me-1" :key="p.id">
<on-the-fly
:type="p.type"
:id="p.id"
:buttonText="p.textAge"
:displayBadge="'true' === 'true'"
action="show">
</on-the-fly>
</span>
</td>
<td>
<a class="btn btn-sm btn-show" :href="getUrl(w)">
{{ $t('show_entity', { entity: $t('the_workflow') }) }}
</a>
</td>
</tr>
</template>
</tab-table>
</template>
<script>
import { mapState, mapGetters } from "vuex";
import TabTable from "./TabTable";
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly';
export default {
name: "MyWorkflows",
components: {
TabTable,
OnTheFly
},
computed: {
...mapState([
'workflows',
]),
...mapGetters([
'isWorkflowsLoaded',
]),
noResults() {
if (!this.isWorkflowsLoaded) {
return false;
} else {
return this.workflows.count === 0;
}
},
},
methods: {
getUrl(w) {
return `/fr/main/workflow/${w.id}/show`;
},
getStep(w) {
const lastStep = w.steps.length - 1
return w.steps[lastStep].currentStep.text;
}
},
}
</script>
<style scoped>
span.outdated {
font-weight: bold;
color: var(--bs-warning);
}
</style>

View File

@@ -22,10 +22,6 @@ const appMessages = {
tab: "Mes notifications",
description: "Liste des notifications reçues et non lues.",
},
my_workflows: {
tab: "Mes workflows",
description: "Liste des workflows en attente d'une action."
},
opening_date: "Date d'ouverture",
social_issues: "Problématiques sociales",
concerned_persons: "Usagers concernés",
@@ -37,16 +33,12 @@ const appMessages = {
From: "Expéditeur",
Subject: "Objet",
Entity: "Associé à",
Step: "Étape",
concerned_users: "Usagers concernés",
Object_workflow: "Objet du workflow",
show_entity: "Voir {entity}",
the_activity: "l'échange",
the_course: "le parcours",
the_action: "l'action",
the_evaluation: "l'évaluation",
the_task: "la tâche",
the_workflow: "le workflow",
StartDate: "Date d'ouverture",
SocialAction: "Action d'accompagnement",
no_data: "Aucun résultats",
@@ -69,4 +61,4 @@ Object.assign(appMessages.fr);
export {
appMessages
};
};

View File

@@ -1,6 +1,12 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import MyCustoms from "../MyCustoms";
import MyWorks from "../MyWorks";
import MyEvaluations from "../MyEvaluations";
import MyTasks from "../MyTasks";
import MyAccompanyingCourses from "../MyAccompanyingCourses";
import MyNotifications from "../MyNotifications";
const debug = process.env.NODE_ENV !== 'production';
@@ -21,7 +27,6 @@ const store = createStore({
},
accompanyingCourses: {},
notifications: {},
workflows: {},
errorMsg: [],
loading: false
},
@@ -44,9 +49,6 @@ const store = createStore({
isNotificationsLoaded(state) {
return !isEmpty(state.notifications);
},
isWorkflowsLoaded(state) {
return !isEmpty(state.workflows);
},
counter(state) {
return {
works: state.works.count,
@@ -55,7 +57,6 @@ const store = createStore({
tasksAlert: state.tasks.alert.count,
accompanyingCourses: state.accompanyingCourses.count,
notifications: state.notifications.count,
workflows: state.workflows.count
}
}
},
@@ -84,9 +85,6 @@ const store = createStore({
//console.log('addNotifications', notifications);
state.notifications = notifications;
},
addWorkflows(state, workflows) {
state.workflows = workflows;
},
setLoading(state, bool) {
state.loading = bool;
},
@@ -182,30 +180,14 @@ const store = createStore({
const url = `/api/1.0/main/notification/my/unread${'?'+ param}`;
makeFetch('GET', url)
.then((response) => {
console.log('notifications', response)
commit('addNotifications', response);
commit('setLoading', false);
})
.catch((error) => {
commit('catchError', error);
throw error;
});
}
break;
case 'MyWorkflows':
if (!getters.isWorflowsLoaded) {
commit('setLoading', true);
const url = '/api/1.0/main/workflow/my';
makeFetch('GET', url)
.then((response) => {
console.log('workflows', response)
commit('addWorkflows', response);
commit('setLoading', false);
})
.catch((error) => {
commit('catchError', error);
throw error;
});
})
;
}
break;
default:

View File

@@ -1,6 +1,6 @@
<template>
<ul class="nav nav-tabs">
<li v-if="allowedTypes.includes('person')" class="nav-item">
<li class="nav-item">
<a class="nav-link" :class="{ active: isActive('person') }">
<label for="person">
<input type="radio" name="person" id="person" v-model="radioType" value="person">
@@ -8,7 +8,7 @@
</label>
</a>
</li>
<li v-if="allowedTypes.includes('thirdparty')" class="nav-item">
<li class="nav-item">
<a class="nav-link" :class="{ active: isActive('thirdparty') }">
<label for="thirdparty">
<input type="radio" name="thirdparty" id="thirdparty" v-model="radioType" value="thirdparty">
@@ -21,16 +21,14 @@
<div class="my-4">
<on-the-fly-person
v-if="type === 'person'"
:action="action"
:query="query"
v-bind:action="action"
ref="castPerson"
>
</on-the-fly-person>
<on-the-fly-thirdparty
v-if="type === 'thirdparty'"
:action="action"
:query="query"
v-bind:action="action"
ref="castThirdparty"
>
</on-the-fly-thirdparty>
@@ -40,17 +38,18 @@
<script>
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
import OnTheFlyThirdparty from 'ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue';
import { postPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
export default {
name: "OnTheFlyCreate",
props: ['action', 'allowedTypes', 'query'],
props: ['action'],
components: {
OnTheFlyPerson,
OnTheFlyThirdparty
},
data() {
return {
type: null
type: 'person' //by default
}
},
computed: {
@@ -62,10 +61,7 @@ export default {
get() {
return this.type;
}
},
},
mounted() {
this.type = (this.allowedTypes.length === 1 && this.allowedTypes.includes('thirdparty')) ? 'thirdparty' : 'person'
}
},
methods: {
isActive(tab) {
@@ -77,7 +73,8 @@ export default {
return this.$refs.castPerson.$data.person;
case 'thirdparty':
let data = this.$refs.castThirdparty.$data.thirdparty;
if (data.address !== undefined && data.address !== null) {
data.name = data.text;
if (data.address !== undefined) {
data.address = { id: data.address.address_id }
} else {
data.address = null;

View File

@@ -1,11 +1,11 @@
<template>
<a v-if="isDisplayBadge" @click="openModal">
<span class="chill-entity" :class="badgeType">
{{ buttonText }}<span v-if="isDead"> ()</span>
</span>
</a>
<a v-else class="btn btn-sm" target="_blank"
<a v-if="isDisplayBadge" @click="openModal">
<span class="chill-entity" :class="badgeType">
{{ buttonText }}<span v-if="isDead"> ()</span>
</span>
</a>
<a v-else class="btn btn-sm" target="_blank"
:class="classAction"
:title="$t(titleAction)"
@click="openModal">
@@ -18,8 +18,7 @@
@close="modal.showModal = false">
<template v-slot:header>
<h3 v-if="parent" class="modal-title">{{ $t(titleModal, {q: parent.text}) }}</h3>
<h3 v-else class="modal-title">{{ $t(titleModal) }}</h3>
<h3 class="modal-title">{{ $t(titleModal) }}</h3>
</template>
<template v-slot:body v-if="type === 'person'">
@@ -30,10 +29,10 @@
ref="castPerson">
</on-the-fly-person>
<div v-if="hasResourceComment">
<h3>{{ $t('onthefly.resource_comment_title') }}</h3>
<blockquote class="chill-user-quote">
{{ parent.comment }}
</blockquote>
<h3>{{ $t('onthefly.resource_comment_title') }}</h3>
<blockquote class="chill-user-quote">
{{ parent.comment }}
</blockquote>
</div>
</template>
@@ -45,27 +44,16 @@
ref="castThirdparty">
</on-the-fly-thirdparty>
<div v-if="hasResourceComment">
<h3>{{ $t('onthefly.resource_comment_title') }}</h3>
<blockquote class="chill-user-quote">
{{ parent.comment }}
</blockquote>
<h3>{{ $t('onthefly.resource_comment_title') }}</h3>
<blockquote class="chill-user-quote">
{{ parent.comment }}
</blockquote>
</div>
</template>
<template v-slot:body v-else-if="parent">
<on-the-fly-thirdparty
:parent="parent"
:action="action"
type="thirdparty"
ref="castThirdparty">
</on-the-fly-thirdparty>
</template>
<template v-slot:body v-else>
<on-the-fly-create
:action="action"
:allowedTypes="allowedTypes"
:query="query"
ref="castNew">
</on-the-fly-create>
</template>
@@ -102,7 +90,7 @@ export default {
OnTheFlyThirdparty,
OnTheFlyCreate
},
props: ['type', 'id', 'action', 'buttonText', 'displayBadge', 'isDead', 'parent', 'allowedTypes', 'query'],
props: ['type', 'id', 'action', 'buttonText', 'displayBadge', 'isDead', 'parent'],
emits: ['saveFormOnTheFly'],
data() {
return {
@@ -114,11 +102,12 @@ export default {
},
computed: {
hasResourceComment() {
return (typeof this.parent !== 'undefined' && this.parent !== null)
&& this.action === 'show'
&& this.parent.type === 'accompanying_period_resource'
&& (this.parent.comment !== null && this.parent.comment !== '')
;
//console.log('hasResourceComment', this.parent);
return (typeof this.parent !== 'undefined' && this.parent !== null)
&& this.action === 'show'
&& this.parent.type === 'accompanying_period_resource'
&& (this.parent.comment !== null && this.parent.comment !== '')
;
},
classAction() {
switch (this.action) {
@@ -128,8 +117,6 @@ export default {
return 'btn-update';
case 'create':
return 'btn-create';
case 'addContact':
return 'btn-tpchild';
}
},
titleAction() {
@@ -140,17 +127,8 @@ export default {
return 'action.edit';
case 'create':
return 'action.create';
case 'addContact':
return 'action.addContact';
}
},
titleCreate() {
return this.allowedTypes.every(t => t === 'person')
? 'onthefly.create.title.person'
: this.allowedTypes.every(t => t === 'thirdparty')
? 'onthefly.create.title.thirdparty'
: 'onthefly.create.title.default'
},
titleModal() {
switch (this.action) {
case 'show':
@@ -158,9 +136,7 @@ export default {
case 'edit':
return 'onthefly.edit.' + this.type;
case 'create':
return this.titleCreate;
case 'addContact':
return 'onthefly.addContact.title';
return 'onthefly.create.title';
}
},
titleMessage() {
@@ -194,8 +170,8 @@ export default {
this.modal.showModal = false;
},
openModal() {
// console.log('## OPEN ON THE FLY MODAL');
// console.log('## type:', this.type, ', action:', this.action);
//console.log('## OPEN ON THE FLY MODAL');
//console.log('## type:', this.type, ', action:', this.action);
this.modal.showModal = true;
this.$nextTick(function() {
//this.$refs.search.focus();
@@ -205,7 +181,7 @@ export default {
this.$data.action = action;
},
saveAction() {
// console.log('saveAction button: create/edit action with', this.type);
console.log('saveAction button: create/edit action with', this.type);
let
type = this.type,
data = {} ;
@@ -217,31 +193,17 @@ export default {
case 'thirdparty':
data = this.$refs.castThirdparty.$data.thirdparty;
/* never executed ? Yes, when editing thirdparty... */
break;
default:
if (typeof this.type === 'undefined') { // action=create or addContact
console.log('will rewrite data');
if (this.action === 'addContact') {
type = 'thirdparty'
data = this.$refs.castThirdparty.$data.thirdparty;
console.log('data original', data);
data.parent = {type: "thirdparty", id: this.parent.id};
// data.civility = {type: 'chill_main_civility', id: civility.id };
// data.profession = {type: 'third_party_profession', id: profession.id };
} else {
console.log('im here')
type = this.$refs.castNew.radioType;
data = this.$refs.castNew.castDataByType();
console.log('saveAction', data)
}
if (typeof this.type === 'undefined') { // action=create
type = this.$refs.castNew.radioType;
data = this.$refs.castNew.castDataByType();
} else {
throw 'error with object type';
}
}
console.log('type', type);
console.log('data', data);
// pass datas to parent
this.$emit('saveFormOnTheFly', { type: type, data: data });
},
@@ -261,8 +223,4 @@ export default {
a {
cursor: pointer;
}
/* .btn-add-contact {
background-color: pink;
} */
</style>

View File

@@ -9,25 +9,15 @@ const ontheflyMessages = {
},
edit: {
person: "Modifier un usager",
thirdparty: "Modifier un tiers",
thirdparty: "Modifier un tiers"
},
create: {
button: "Créer \"{q}\"",
title: {
default: "Création d'un nouvel usager ou d'un tiers professionnel",
person: "Création d'un nouvel usager",
thirdparty: "Création d'un nouveau tiers professionnel",
},
title: "Création d'un nouvel usager ou d'un tiers professionnel",
person: "un nouvel usager",
thirdparty: "un nouveau tiers professionnel"
},
addContact: {
title: "Créer un contact pour {q}"
},
resource_comment_title: "Un commentaire est associé à cet interlocuteur",
addContact: {
title: "Créer un contact pour {q}"
}
resource_comment_title: "Un commentaire est associé à cet interlocuteur"
}
}
}

View File

@@ -1,10 +1,10 @@
<template>
<div class="confidential">
<div :class="{ 'blur': isBlurred }">
<div :class="classes">
<div class="confidential-content" :class="{ 'blur': isBlurred }">
<slot name="confidential-content"></slot>
</div>
<div>
<i class="fa fa-eye toggle" :class="positionBtn" aria-hidden="true" @click="toggleBlur"></i>
<i class="fa fa-eye toggle" aria-hidden="true" @click="toggleBlur"></i>
</div>
</div>
</template>
@@ -12,7 +12,6 @@
<script>
export default {
name: "Confidential",
props: ['positionBtnFar'],
data() {
return {
isBlurred: true,
@@ -20,14 +19,9 @@ export default {
},
methods : {
toggleBlur() {
console.log(this.positionBtnFar);
console.log('toggle blur');
this.isBlurred = !this.isBlurred;
},
},
computed: {
positionBtn() {
return this.positionBtnFar ? 'toggle-far' : 'toggle-close'
}
}
}
</script>
@@ -35,5 +29,18 @@ export default {
<style scoped lang='scss'>
.confidential{
align-items: center;
display: flex;
}
.toggle{
margin-top: 28px;
cursor: pointer;
display: block;
float: right;
margin-right: 20px;
}
.blur {
-webkit-filter: blur(5px);
-moz-filter: blur(5px);
filter: blur(5px);
}
</style>

View File

@@ -5,7 +5,7 @@
<component :is="component" class="address" :class="multiline">
<div v-if="isConfidential">
<confidential :positionBtnFar="true">
<confidential>
<template v-slot:confidential-content>
<div v-if="isMultiline === true">
<p v-for="(l, i) in address.lines" :key="`line-${i}`">
@@ -27,6 +27,7 @@
</p>
</div>
</template>
</confidential>
</div>
@@ -93,7 +94,6 @@ export default {
return this.isMultiline === true ? "multiline" : "";
},
isConfidential() {
console.log(this.address.confidential)
return this.address.confidential;
}
}

View File

@@ -5,7 +5,7 @@
<div>
<div class="item-row col">
<h2>{{ w.title }}</h2>
<h2>Workflow</h2>
<div class="flex-grow-1 ms-3 h3">
<div class="visually-hidden">
{{ w.relatedEntityClass }}

View File

@@ -12,8 +12,6 @@
:relatedEntityClass="this.relatedEntityClass"
:relatedEntityId="this.relatedEntityId"
:workflowsAvailables="workflowsAvailables"
:preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
:goToGenerateWorkflowPayload="this.goToGenerateWorkflowPayload"
@go-to-generate-workflow="goToGenerateWorkflow"
></pick-workflow>
@@ -38,7 +36,6 @@
:relatedEntityId="this.relatedEntityId"
:workflowsAvailables="workflowsAvailables"
:preventDefaultMoveToGenerate="this.$props.preventDefaultMoveToGenerate"
:goToGenerateWorkflowPayload="this.goToGenerateWorkflowPayload"
@go-to-generate-workflow="this.goToGenerateWorkflow"
></pick-workflow>
</template>
@@ -86,10 +83,6 @@ export default {
required: false,
default: false,
},
goToGenerateWorkflowPayload: {
required: false,
default: {}
},
},
data() {
return {
@@ -112,7 +105,7 @@ export default {
this.modal.showModal = true;
},
goToGenerateWorkflow(data) {
console.log('go to generate workflow intercepted', data);
console.log('go to generate workflow intercepted');
this.$emit('goToGenerateWorkflow', data);
}
},

View File

@@ -37,10 +37,6 @@ export default {
required: false,
default: false,
},
goToGenerateWorkflowPayload: {
required: false,
default: {}
},
},
emits: ['goToGenerateWorkflow'],
methods: {
@@ -55,7 +51,7 @@ export default {
window.location.assign(this.makeLink(workflowName));
}
this.$emit('goToGenerateWorkflow', {event, workflowName, link: this.makeLink(workflowName), payload: this.goToGenerateWorkflowPayload});
this.$emit('goToGenerateWorkflow', {event, workflowName, link: this.makeLink(workflowName)});
}
}
}

View File

@@ -46,8 +46,7 @@ const messages = {
person: "Quitter la page et ouvrir la fiche de l'usager",
thirdparty: "Quitter la page et voir le tiers",
},
refresh: 'Rafraîchir',
addContact: 'Ajouter un contact'
refresh: 'Rafraîchir'
},
nav: {
next: "Suivant",
@@ -70,8 +69,7 @@ const messages = {
},
holder: "Titulaire",
years_old: "an | {n} an | {n} ans",
residential_address: "Adresse de résidence",
located_at: "réside chez"
}
}
};

View File

@@ -59,7 +59,7 @@
must be shown in such list
#}
{%- if render == 'list' -%}
<li class="chill-entity entity-address {% if address.confidential %} confidential toggle-far-twig {% endif %}">
<li class="chill-entity entity-address {% if address.confidential %}confidential{% endif %}">
{% if options['with_picto'] %}
<i class="fa fa-li fa-map-marker"></i>
{% endif %}
@@ -68,7 +68,7 @@
{%- endif -%}
{%- if render == 'inline' -%}
<span class="chill-entity entity-address {% if address.confidential %} confidential toggle-far-twig {% endif %}">
<span class="chill-entity entity-address {% if address.confidential %}confidential{% endif %}">
{% if options['with_picto'] %}
<i class="fa fa-fw fa-map-marker"></i>
{% endif %}
@@ -77,7 +77,7 @@
{%- endif -%}
{%- if render == 'bloc' -%}
<div class="chill-entity entity-address {% if address.confidential %} confidential toggle-close-twig {% endif %}">
<div class="chill-entity entity-address {% if address.confidential %}confidential{% endif %}">
{% if options['has_no_address'] == true and address.isNoAddress == true %}
{% if address.postCode is not empty %}
<div class="address{% if options['multiline'] %} multiline{% endif %}{% if options['with_delimiter'] %} delimiter{% endif %}">

View File

@@ -18,10 +18,8 @@
{% for entity in entities %}
<tr>
<td>{{ entity.name }}</td>
<td>
{{ entity.phonenumber1|chill_format_phonenumber }}
</td>
<td>{{ entity.phonenumber2|chill_format_phonenumber }}</td>
<td>{{ entity.phonenumber1 }}</td>
<td>{{ entity.phonenumber2 }}</td>
<td>{{ entity.email }}</td>
<td>
{% if entity.address is not null %}

View File

@@ -3,8 +3,6 @@
{% if transition_form is not null %}
{{ form_start(transition_form) }}
{{ form_errors(transition_form) }}
{% set step = entity_workflow.currentStepChained %}
{% set labels = workflow_metadata(entity_workflow, 'label', step.currentStep) %}
{% set label = labels is null ? step.currentStep : labels|localize_translatable_string %}
@@ -62,10 +60,8 @@
{{ form_row(transition_form.freezeAfter) }}
{% endif %}
<div id="futureDests">
<div id="futureDestUsers">
{{ form_row(transition_form.future_dest_users) }}
{{ form_row(transition_form.future_dest_emails) }}
</div>
<p>{{ form_label(transition_form.comment) }}</p>
@@ -86,23 +82,13 @@
<p>{{ 'workflow.This workflow is finalized'|trans }}</p>
{% else %}
<p>{{ 'workflow.You are not allowed to apply a transition on this workflow'|trans }}</p>
{% if entity_workflow.currentStep.destUser|length > 0 %}
<p><b>{{ 'workflow.Only those users are allowed'|trans }}&nbsp;:</b></p>
<ul>
{% for u in entity_workflow.currentStep.destUser -%}
<li>{{ u|chill_entity_render_box }}</li>
{%- endfor %}
</ul>
{% endif %}
<p>{{ 'workflow.Only those users are allowed'|trans }}:</p>
{% if entity_workflow.currentStep.destUserByAccessKey|length > 0 %}
<p><b>{{ 'workflow.Those users are also granted to apply a transition by using an access key'|trans }}&nbsp;:</b></p>
<ul>
{% for u in entity_workflow.currentStep.destUserByAccessKey %}
<li>{{ u|chill_entity_render_box }}</li>
{% endfor %}
</ul>
{% endif %}
<ul>
{% for u in entity_workflow.currentStep.destUser -%}
<li>{{ u|chill_entity_render_box }}</li>
{%- endfor %}
</ul>
{% endif %}
</div>

View File

@@ -7,7 +7,7 @@
<div data-list-workflows="1"
data-workflows="{{ entity_workflows_json|json_encode|e('html_attr') }}"
data-allow-create="{{ acl }}"
data-related-entity-class="{{ relatedEntityClass }}"
data-related-entity-id="{{ relatedEntityId }}"
data-workflows-availables="{{ workflows_available|json_encode()|e('html_attr') }}"
data-related-entity-class="{{ blank_workflow.relatedEntityClass }}"
data-related-entity-id="{{ blank_workflow.relatedEntityId }}"
data-workflows-availables="{{ workflows_availables|json_encode()|e('html_attr') }}"
></div>

View File

@@ -69,26 +69,15 @@
</blockquote>
</div>
{% endif %}
{% if loop.last and step.allDestUser|length > 0 %}
{% if loop.last and step.destUser|length > 0 %}
<div class="item-row separator">
<div>
{% if step.destUser|length > 0 %}
<p><b>{{ 'workflow.Users allowed to apply transition'|trans }}&nbsp;: </b></p>
<ul>
{% for u in step.destUser %}
<li>{{ u|chill_entity_render_box }}</li>
{% endfor %}
</ul>
{% endif %}
{% if step.destUserByAccessKey|length > 0 %}
<p><b>{{ 'workflow.Those users are also granted to apply a transition by using an access key'|trans }}&nbsp;:</b></p>
<ul>
{% for u in step.destUserByAccessKey %}
<li>{{ u|chill_entity_render_box }}</li>
{% endfor %}
</ul>
{% endif %}
<p><b>{{ 'workflow.Users allowed to apply transition'|trans }}&nbsp;: </b></p>
<ul>
{% for u in step.destUser %}
<li>{{ u|chill_entity_render_box }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}

View File

@@ -1,29 +0,0 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title 'workflow.Delete workflow ?'|trans %}
{% block display_content %}
<h2>
{{ handler.entityTitle(entityWorkflow) }}
</h2>
{% include handler.template(entityWorkflow) with handler.templateData(entityWorkflow)|merge({
'display_action': false
}) %}
{% endblock %}
{% block content %}
<div class="container chill-md-10">
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'workflow.Delete workflow ?'|trans,
'confirm_question' : 'workflow.Are you sure you want to delete this workflow ?'|trans,
'display_content' : block('display_content'),
'cancel_route' : 'chill_main_workflow_show',
'cancel_parameters' : {'id' : entityWorkflow.id},
'form' : delete_form
} ) }}
</div>
{% endblock %}

View File

@@ -21,12 +21,10 @@
{{ encore_entry_link_tags('mod_wopi_link') }}
{% endblock %}
{% import '@ChillMain/Workflow/macro_breadcrumb.html.twig' as macro %}
{% block content %}
<div class="col-10 workflow">
<h1 class="mb-5">{{ block('title') }}</h1>
{# handler_template:
- src/Bundle/ChillPersonBundle/Resources/views/Workflow/_evaluation.html.twig
- src/Bundle/ChillPersonBundle/Resources/views/Workflow/_accompanying_period_work.html.twig
@@ -34,26 +32,11 @@
#}
<section class="step my-4">
<div class="mb-5">
<h2>{{ handler.entityTitle(entity_workflow) }}</h2>
{{ macro.breadcrumb({'entity_workflow': entity_workflow}) }}
{% include handler_template_title with handler_template_data|merge({'breadcrumb': true }) %}
</div>
{% include handler_template with handler_template_data|merge({'display_action': true }) %}
{% if is_granted('CHILL_MAIN_WORKFLOW_DELETE', entity_workflow) %}
<ul class="record_actions">
<li>
<a class="btn btn-delete"
href="{{ chill_path_add_return_path('chill_main_workflow_delete', {'id': entity_workflow.id}) }}"
>
{{ 'workflow.Delete workflow'|trans }}
</a>
</li>
</ul>
{% endif %}
</section>
<section class="step my-4">{% include '@ChillMain/Workflow/_follow.html.twig' %}</section>
<section class="step my-4">{% include '@ChillMain/Workflow/_decision.html.twig' %}</section>{#
<section class="step my-4">{% include '@ChillMain/Workflow/_comment.html.twig' %}</section> #}

View File

@@ -8,10 +8,9 @@
{% block content %}
<div class="col-10 workflow">
<h1 class="mb-5">{{ block('title') }}</h1>
<ul class="nav nav-pills justify-content-center">
<li class="nav-item">
<a href="{{ path('chill_main_workflow_list_subscribed') }}"
@@ -25,24 +24,8 @@
{{ 'workflow.dest'|trans }}
</a>
</li>
<li class="nav-item">
<a href="{{ path('chill_main_workflow_list_previous_without_reaction') }}"
class="nav-link {% if step == 'previous_without_reaction' %}active{% endif %}">
{{ 'workflow.Previous dest without reaction'|trans }}
</a>
</li>
<li class="nav-item">
<a href="{{ path('chill_main_workflow_list_previous_transitionned') }}"
class="nav-link {% if step == 'previous_transitionned' %}active{% endif %}">
{{ 'workflow.Previous transitionned'|trans }}
</a>
</li>
</ul>
{% if help is defined %}
<p style="margin-top: 2rem;">{{ help|trans }}</p>
{% endif %}
{% if workflows|length == 0 %}
<p class="chill-no-data-statement">{{ 'workflow.No workflow'|trans }}</p>
{% else %}
@@ -53,24 +36,26 @@
<button type="button" class="accordion-button collapsed"
data-bs-toggle="collapse" data-bs-target="#flush-collapse-{{ l.entity_workflow.id }}"
aria-expanded="false" aria-controls="flush-collapse-{{ l.entity_workflow.id }}">
<div class="item-row col">
<h2>
{{ l.handler.entityTitle(l.entity_workflow) }}
{{ 'workflow_'|trans }}
</h2>
{% include l.handler.templateTitle(l.entity_workflow) with l.handler.templateTitleData(l.entity_workflow)|merge({
'description': true,
'add_classes': 'ms-3 h3'
}) %}
</div>
</button>
<div>
{{ macro.breadcrumb(l) }}
</div>
{{ macro.breadcrumb(l) }}
</div>
<div id="flush-collapse-{{ l.entity_workflow.id }}"
class="accordion-collapse collapse"
aria-labelledby="flush-heading-{{ l.entity_workflow.id }}"
data-bs-parent="#workflow-fold">
<div class="item-row flex-column">
{% include l.handler.template(l.entity_workflow) with l.handler.templateData(l.entity_workflow)|merge({
'display_action': false
@@ -93,13 +78,6 @@
</div>
<div class="item-col">
<ul class="record_actions">
{% if is_granted('CHILL_MAIN_WORKFLOW_DELETE', l.entity_workflow) %}
<li>
<a class="btn btn-delete"
href="{{ chill_path_add_return_path('chill_main_workflow_delete', {'id': l.entity_workflow.id}) }}"
></a>
</li>
{% endif %}
<li>
<a href="{{ path('chill_main_workflow_show', {'id': l.entity_workflow.id}) }}"
class="btn btn-show">
@@ -109,7 +87,7 @@
</ul>
</div>
</div>
</div>
</div>
{% endfor %}

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