Compare commits

...

277 Commits

Author SHA1 Message Date
da75f5b17f personHasCenter validation removed from Person entity 2021-11-15 11:32:57 +01:00
5606b714cd changelog updated 2021-11-11 13:38:32 +01:00
f92c500657 Merge branch 'master' of gitlab.com:Chill-Projet/chill-bundles 2021-11-11 13:37:11 +01:00
1146bd666f unnecessary whitespace removed from person banner after person-id + double parentheses removed 2021-11-11 13:36:49 +01:00
Pol Dellaiera
5e5dcaefe7 Fix implicit variable creation. 2021-11-09 16:22:16 +01:00
Pol Dellaiera
a1b381a3ea Fix bug and remove obsolete issue. 2021-11-09 15:20:25 +01:00
Pol Dellaiera
5615734123 Update baseline - remove obsolete errors. 2021-11-09 15:17:55 +01:00
Pol Dellaiera
2eb30d2ae8 Fix issues reported by PHPStan. 2021-11-09 15:17:24 +01:00
Pol Dellaiera
48ea67968e Update PHPStan configuration.
Update paths - add paths to ignore.
2021-11-09 15:16:06 +01:00
Pol Dellaiera
9fc397f048 Fix PHPStan un-ignorable issues. 2021-11-09 13:51:25 +01:00
Pol Dellaiera
a19a5803e8 Update baseline - add new errors. 2021-11-09 13:49:08 +01:00
Pol Dellaiera
bf155f6967 Update PHPStan configuration.
Update paths - simplify.
2021-11-09 13:48:15 +01:00
Pol Dellaiera
6a9e133256 Add phpstan/extension-installer. 2021-11-09 13:39:24 +01:00
Pol Dellaiera
fb4b586cf0 Update baseline - add new errors. 2021-11-09 13:37:01 +01:00
Pol Dellaiera
6b60c46ad3 Update baseline - remove ignored errors. 2021-11-09 13:36:09 +01:00
Pol Dellaiera
774b5b69d9 Enable phpstan/phpstan-strict-rules. 2021-11-09 13:35:44 +01:00
2382e7f44b Merge branch 'feat/add-phpstan-configuration-and-baseline' into 'master'
Add PHPStan project with level 1.

This PR: Add basic configuration files with basic baseline.


See merge request Chill-Projet/chill-bundles!191
2021-11-09 11:31:21 +00:00
Pol Dellaiera
e2ab3bfc6e Add PHPStan project with level 1. 2021-11-09 11:31:20 +00:00
b2d6c82cbe update changelog with last release 2021-11-09 09:39:05 +01:00
9247cd3546 fix saving person 2021-11-08 15:31:19 +01:00
ec6828f128 Merge branch 'features/person-normalization-resolver-center-dynamically' into 'master'
Use centerResolverDispatcher to normalize a person's center


# Description of changes

There is a normalizer for a person, which include a property "center":

```json
{

    "type": "person",
    "id": 4362539,
    "text": "Diakite BAH",
    "firstName": "Diakite",
    "lastName": "BAH",
    "center": {
        "id": 475,
        "type": "center",
        "name": "Nord Vendée"
    },
    "phonenumber": "",
    "mobilenumber": "",
    "altNames": [ ],
    "gender": "woman",
    "gender_numeric": 1,
    // ...
}
```

Previously, the center was the center attached to the person in the database.

But since September, version 2.0 allow to resolve the center dynamically, for instance with the usage of address. This resolution is done through `CenterResolverDispatcher`.

This `CenterResolverDispatcher` is now used into person normalization.

As a consequence, the center may now be:

* null;
* a center;
* an array of center;

Thoses case are taken into account into `PersonRenderBox` in Vue.



# Issues related

Any issue related.

# Tests

Any new tests.

See merge request Chill-Projet/chill-bundles!205
2021-11-08 12:22:11 +00:00
7399d0aa9e Use centerResolverDispatcher to normalize a person's center 2021-11-08 12:22:11 +00:00
19b469259d Merge branch 'bugfix/acl-add-roles-misc-places' into 'master'
Add voter to various places

See merge request Chill-Projet/chill-bundles!207
2021-11-08 12:21:15 +00:00
5c037ca18f Merge branch 'master' into 'bugfix/acl-add-roles-misc-places' [ci-skip]
# Conflicts:
#   CHANGELOG.md
2021-11-08 12:20:26 +00:00
nobohan
c979de962e fix conflict in CHANGELOG 2021-11-08 12:41:11 +01:00
nobohan
061197e52e upd CHANGELOG 2021-11-08 12:21:06 +01:00
e786c40679 Merge branch 'issue124_ACCent_ménage_editForm' into 'master'
Household edit: end date field deleted


# Description of changes

End date field removed from household edit form.


# Issues related

* internal: https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/265
* ACCent: https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/124

# Tests

No tests

See merge request Chill-Projet/chill-bundles!202
2021-11-08 11:03:38 +00:00
e4f8ada236 Household edit: end date field deleted 2021-11-08 11:03:37 +00:00
21e419b338 Merge branch 'issue126_household_list' into 'master'
household list of accompanying periods + upgrade DBAL version to 3.1


# Description of changes

* Household: List of accompanying periods shows all periods linked to current household members for which viewing access is granted to current user.
* Upgrade DBAL to 3.1


# Issues related

* inernal: https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/274
* ACCent: https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/126

# Tests

Not yet written

See merge request Chill-Projet/chill-bundles!204
2021-11-08 10:57:14 +00:00
7fabe0214e household list of accompanying periods + upgrade DBAL version to 3.1 2021-11-08 10:57:14 +00:00
nobohan
fa05a6856a person: add civility: entity, migration, form, twig, config 2021-11-08 11:41:45 +01:00
nobohan
1dbf29beea person: avoid js error when personAcceptEmail is null 2021-11-08 11:04:20 +01:00
nobohan
bddcdd7de2 person: add preferrred_choices for countries and languages 2021-11-08 10:42:12 +01:00
092ea4d57f Merge branch 'bugfix/activity-fix-role-inheritance' into 'master'
Bugfix/activity fix role inheritance


# Description of changes

* fix the inheritance of the role "ACTIVITY_FULL"
* add missing ACL in menu


# Issues related

* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/163

# Tests

Any new tests

See merge request Chill-Projet/chill-bundles!206
2021-11-05 14:13:00 +00:00
f16f45f3f3 Bugfix/activity fix role inheritance 2021-11-05 14:13:00 +00:00
5ce2fe3295 Merge branch 'feature/suivi-157-affiche-alt-names-list-with-periods' into 'master'
Show alt names in person search results


# Description of changes

* Ajoute l'adresse actuelle de la personne dans les résultats de recherche;
* affiche les altNames dansl es réslttats de recherche



# Issues related


* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/157

# Tests

Some tests, which were related to the old way on person address was computed, where removed.

See merge request Chill-Projet/chill-bundles!195
2021-11-05 12:52:31 +00:00
5111a0ff6a Show alt names in person search results 2021-11-05 12:52:31 +00:00
74df496e38 Merge branch 'issue47_ACCent_householdAddress_ordering' into 'master'
Ordering household addresses


# Description of changes

Ordering by id added so that last created address displays first.


# Issues related

* internal: https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/275
* ACCent: https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/47

# Tests

No tests written.

See merge request Chill-Projet/chill-bundles!203
2021-11-05 12:34:35 +00:00
fd2d74c9f5 Ordering household addresses 2021-11-05 12:34:35 +00:00
b615f0c79f Merge branch 'issue73_ACCent_displayOf_problématiques' into 'master'
Display of social issues with parent issue and with badge


# Description of changes

For social work action: social issues are displayed with their parent issue.
Banner was fixed so that it contains all the context info.


# Issues related

* internal: https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/277
* ACCent: https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/73

# Tests

No tests.

See merge request Chill-Projet/chill-bundles!201
2021-11-05 12:33:10 +00:00
97859e9c1f Display of social issues with parent issue and with badge 2021-11-05 12:33:10 +00:00
6642b87168 Merge branch 'bugfixes/tasks-list' into 'master'
Bugfixes/tasks list


# Description of changes

<!--
  describe here the change of your MR. It can be either a text, or a bullet list
  for changes
-->

* different title for task list and my title
* fixes link to tasks in alert


# Issues related

<!--
  list the issues related to this MR.

  It may be client issues, or dev issues
-->

no issues related

# Tests

The tests for listing task does apply

See merge request Chill-Projet/chill-bundles!200
2021-11-05 12:31:41 +00:00
35d807cab0 Bugfixes/tasks list 2021-11-05 12:31:41 +00:00
e1677cd2b6 Merge branch 'feature/household-accept-members-without-position' into 'master'
An household can have members without position

See merge request Chill-Projet/chill-bundles!189
2021-11-05 09:26:16 +00:00
df0cb8596b update changelog [ci-skip] 2021-11-04 23:43:24 +01:00
250bd29ab3 add voter for documents 2021-11-04 23:40:30 +01:00
nobohan
8de78c7584 person: add prefered_choices for language (WIP) 2021-11-04 16:20:08 +01:00
nobohan
84ab4f8d1f person: add the possibility of form data is null on CommentType 2021-11-04 15:56:15 +01:00
261810374f Merge branch 'issue83_ACCent_addDocument_toAction' into 'master'
cascade persist added to Activity::documents

See merge request Chill-Projet/chill-bundles!197
2021-11-04 11:44:57 +00:00
8f541c8418 Merge branch 'master' into 'issue83_ACCent_addDocument_toAction'
# Conflicts:
#   CHANGELOG.md
2021-11-04 11:40:56 +00:00
b69cee84b6 Update CHANGELOG.md 2021-11-04 09:12:06 +00:00
b7e0753dbf changelog fixed 2021-11-04 10:09:08 +01:00
9c57d21e5a Merge branch 'issue153_ACCent_activity_admin' into 'master'
Issue153_accent_activity_admin

See merge request Chill-Projet/chill-bundles!193
2021-11-04 08:57:13 +00:00
c03b925bd9 Merge branch 'master' into 'issue153_ACCent_activity_admin'
# Conflicts:
#   CHANGELOG.md
#   src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php
2021-11-04 08:52:32 +00:00
6fdbefa4c8 changelog updated and comments removed 2021-11-04 09:50:25 +01:00
13b43ace39 update of changelog.md 2021-11-04 09:45:35 +01:00
12c3bfa578 Merge branch 'improve_localisation_271' 2021-11-03 16:18:53 +01:00
nobohan
52778a7051 upd CHANGELOG 2021-11-03 16:17:33 +01:00
nobohan
a768563cd0 location: display the error message in case of wrong phone number or email 2021-11-03 16:16:51 +01:00
nobohan
4011fc6e77 location: client side validation 2021-11-03 16:16:51 +01:00
nobohan
51938a99db location: allow null value for location in Calendar 2021-11-03 16:16:51 +01:00
nobohan
c1f4e77293 location: allow null value for location in Activity 2021-11-03 16:16:51 +01:00
nobohan
bfb219746a location: client-side form validation 2021-11-03 16:16:51 +01:00
nobohan
4e72bdead5 location: code refactoring: move saveNewLocation + order of fields 2021-11-03 16:16:51 +01:00
nobohan
e52880bb53 location: filter location-type by active and availableForUsers 2021-11-03 16:16:51 +01:00
nobohan
0439e6a821 location: filter location endpoint by NULL names 2021-11-03 16:16:51 +01:00
72337a8fba Merge branch 'issue74_ACCent_rename_evaluations' into 'master'
section title evaluations changed for accompanyingcoursework edit

See merge request Chill-Projet/chill-bundles!196
2021-11-03 15:16:01 +00:00
645603a98f Merge branch 'master' into improve_localisation_271 2021-11-03 16:09:53 +01:00
c6d7de3e58 Merge branch 'bugfix/authorization-helper-fix-constructor' into 'master'
authorization helper: fix consructor

See merge request Chill-Projet/chill-bundles!194
2021-11-03 14:59:08 +00:00
8c5bf6786b increase memory on gitlab-ci operations 2021-11-03 15:46:00 +01:00
7c5d0fce51 update changelog 2021-11-03 15:36:06 +01:00
35154f5ae1 fix constructor into acl aware repository 2021-11-03 15:35:38 +01:00
6911ace412 Refactor authorization helper to separate some methods
Methods regarding to role hierarchi are now delegated to a parent role helper.
2021-11-03 15:35:38 +01:00
87e16ec24f authorization helper: fix consructor 2021-11-03 15:35:38 +01:00
765a450bb9 update changelog with issues into vendee changelog 2021-11-03 15:33:31 +01:00
nobohan
93880f7010 upd CHANGELOG 2021-11-03 14:55:33 +01:00
nobohan
0231433a6c location: display the error message in case of wrong phone number or email 2021-11-03 14:45:15 +01:00
b2fe024534 Code that causes error commented: UserMenuBuilder.php 2021-11-03 13:27:32 +00:00
39e0e01eb8 cascade persist added to Activity::documents 2021-11-03 14:15:48 +01:00
nobohan
2aa588037a location: client side validation 2021-11-03 13:51:15 +01:00
nobohan
addb362478 location: allow null value for location in Calendar 2021-11-03 13:43:34 +01:00
nobohan
819fc8af46 location: allow null value for location in Activity 2021-11-03 13:42:35 +01:00
e7ad96aaf7 Add a template for merge request [ci-skip] 2021-11-03 12:02:09 +01:00
nobohan
f4bd55262a location: client-side form validation 2021-11-03 11:59:06 +01:00
eebff23282 section title evaluations changed for accompanyingcoursework edit 2021-11-03 11:49:31 +01:00
2d33ae26d8 Merge branch '106_tasks_to_parcours' 2021-11-03 11:45:40 +01:00
7a384f9657 Separate cache:clear from doctrine:fixtures:load in ci
This is an attempt to fix the bug which replace references by NULL
values
2021-11-03 11:43:57 +01:00
nobohan
c8bc6ac495 location: code refactoring: move saveNewLocation + order of fields 2021-11-03 11:34:52 +01:00
b0471c4851 translation fixes for aside activities 2021-11-03 10:56:28 +01:00
6d248ab47b Activity link added to admin homepage 2021-11-03 10:55:51 +01:00
nobohan
999658e792 location: filter location-type by active and availableForUsers 2021-11-03 10:27:58 +01:00
nobohan
1646740382 location: filter location endpoint by NULL names 2021-11-03 09:59:40 +01:00
94e84fbdf0 Merge branch 'blur_confidential_info' into 'master'
Blur confidential info

See merge request Chill-Projet/chill-bundles!172
2021-10-30 00:22:41 +00:00
20cebfc517 Merge branch '129_ACCent_gender_display' into 'master'
129_accent_gender_display

See merge request Chill-Projet/chill-bundles!187
2021-10-30 00:22:05 +00:00
e9d20a56ff show members without position in list 2021-10-30 02:08:31 +02:00
576ee49da0 update changelog 2021-10-30 01:08:52 +02:00
8214fec217 Merge remote-tracking branch 'origin/master' into 106_tasks_to_parcours 2021-10-30 01:08:05 +02:00
e0cb5a88bd rewrite task list action 2021-10-30 00:41:28 +02:00
c63b1015e1 add indexes for searching task by end date 2021-10-30 00:40:15 +02:00
35a27de216 update jsonb exists method by using question mark escaping 2021-10-30 00:25:25 +02:00
4dc29435dc changelog entries removed... moved to changelog at root 2021-10-29 16:31:22 +02:00
db15a3d53c adapta list of tasks for a person 2021-10-29 16:26:19 +02:00
059a0b075c review processed 2021-10-29 12:50:01 +02:00
4017f8db48 refactor list by course: use acl aware repository 2021-10-28 14:41:19 +02:00
nobohan
046f65f5ff person: re-add accpet email and add possibility of hidding this field 2021-10-28 09:45:27 +02:00
27db6ddf0c Merge branch 'fix_double_search_button' into 'master'
Fix double search button

See merge request Chill-Projet/chill-bundles!188
2021-10-28 07:03:50 +00:00
nobohan
c90f9ee5bc add mod_input_address_index to collection event: better addition of the event listener to the DOM 2021-10-28 08:07:01 +02:00
nobohan
0bc8986aa7 upd CHANGELOG for fix_double_search_button 2021-10-28 07:42:08 +02:00
nobohan
56019cad99 delete double actions buttons on search person page 2021-10-28 07:40:03 +02:00
4da32dc5ca fix filtering of new tasks 2021-10-28 01:05:36 +02:00
e63d645f8a fix return path in tasks 2021-10-28 00:50:18 +02:00
97dbc4bc16 add more filtering possibilities with order helper 2021-10-28 00:11:05 +02:00
2bbc6bd158 Merge remote-tracking branch 'origin/improve_location' 2021-10-27 16:50:17 +02:00
aea5e9b1d7 Merge remote-tracking branch 'origin/improve_location' into 106_tasks_to_parcours 2021-10-27 16:49:34 +02:00
4287ca37ae changelog note added 2021-10-27 15:28:54 +02:00
07ed6b0fdf no gender defined -> no icon displayed 2021-10-27 15:26:27 +02:00
8e0a22974b Merge remote-tracking branch 'origin/master' into 106_tasks_to_parcours 2021-10-27 13:45:02 +02:00
b4b661882a remove dump 2021-10-27 13:40:55 +02:00
f4fb375fd1 add filtering in task list 2021-10-27 13:32:52 +02:00
691c5ffd21 improve filter order by adding checkboxes 2021-10-27 13:32:33 +02:00
a09c824726 changelogs: info added 2021-10-27 13:09:41 +02:00
59118c8eed Merge branch 'issue88_rename_field' into 'master'
field label for duration of activity

See merge request Chill-Projet/chill-bundles!178
2021-10-27 10:18:00 +00:00
c4c75199d6 Merge branch 'fix_display_dates' into 'master'
Correct formatting of birth- and deathdate

See merge request Chill-Projet/chill-bundles!185
2021-10-27 10:17:16 +00:00
333a4d94b2 layout task list 2021-10-27 11:57:51 +02:00
3f869e9ca5 further implementation in vue elements 2021-10-27 11:14:27 +02:00
5cf94a5ed6 implementation of blur effect for list of thirdparties 2021-10-27 09:41:44 +02:00
965ea528e3 adaptations for acl with tasks 2021-10-26 18:05:06 +02:00
6921817853 Merge branch 'fix/accompanying_period-work-creation-date' into 'master'
accompanying course work: remove display of creation date

See merge request Chill-Projet/chill-bundles!186
2021-10-26 15:56:53 +00:00
nobohan
532efb1787 accompanying course work: changelog 2021-10-26 17:17:04 +02:00
nobohan
0fa3ff4c16 accompanying course work: handle case end date is null 2021-10-26 17:13:41 +02:00
nobohan
d2eb7b471e accompanying course work: remove display of creation date 2021-10-26 16:24:45 +02:00
nobohan
816855e6f8 mod input address: add an event listener to add this component for collections 2021-10-26 14:12:53 +02:00
nobohan
f6806f7743 person: new translation for accept SMS 2021-10-26 14:11:10 +02:00
nobohan
69ae252da6 person: delete accept Email 2021-10-26 14:11:10 +02:00
nobohan
b800b62e88 person: capitalise place of birth (frontend + backend) 2021-10-26 14:11:10 +02:00
nobohan
6a1cf4eb92 person: capitalize entry in person form 2021-10-26 14:11:10 +02:00
nobohan
f44566037c person: fix showHide import/export 2021-10-26 14:11:10 +02:00
c1a845e3e1 display of eye-icon fixed 2021-10-26 11:35:26 +02:00
4096e0d4df undefined condition added 2021-10-26 11:05:13 +02:00
00ad7a74d6 correct formatting of birth- and deathdate 2021-10-26 10:59:19 +02:00
nobohan
1b7cc2be7a add about improve_location MR in changelog 2021-10-25 11:36:18 +02:00
nobohan
526ec52c8d location admin: translations 2021-10-25 11:22:56 +02:00
nobohan
82a679c233 improve location: admin menu 2021-10-25 11:16:17 +02:00
nobohan
21f463ccb9 improve location: correct migration 2021-10-25 10:50:14 +02:00
nobohan
911e709a74 improve location: customizeQuery 2021-10-25 09:34:05 +02:00
nobohan
c46065d9c5 Merge remote-tracking branch 'origin/improve_location-fix-crud' into improve_location
merge...
2021-10-25 09:30:17 +02:00
nobohan
625c43c0b9 improve location: form config 2021-10-25 09:27:50 +02:00
bae06fcc9c Merge remote-tracking branch 'origin/master' into 106_tasks_to_parcours 2021-10-22 17:58:26 +02:00
2f053d3b5f Merge branch 'features/list-possible-user-referral-period' into 'master'
Features/list possible user referral period

See merge request Chill-Projet/chill-bundles!180
2021-10-22 15:54:06 +00:00
c4da6a436b Merge remote-tracking branch 'origin/master' into 106_tasks_to_parcours 2021-10-22 17:52:57 +02:00
4d55b0582c change visibility of methods in LocationCotnroller 2021-10-22 17:25:54 +02:00
693a2889bc fix query customization in crud controller 2021-10-22 17:24:05 +02:00
nobohan
913eb5f229 admin location: filter items in twig 2021-10-22 14:13:54 +02:00
d009d09215 some adjustments to the application of blur effect...incomplete 2021-10-22 12:35:27 +02:00
nobohan
8c96aae988 location admin: menu for location admin 2021-10-22 12:30:52 +02:00
nobohan
ece7ec032d location admin: correct missing dep 2021-10-22 12:21:23 +02:00
nobohan
154416cddf location admin: add active field on Location and LocationType 2021-10-22 12:14:32 +02:00
5869236af1 merge remote into local branch issue fixed 2021-10-22 11:53:13 +02:00
nobohan
7dc4590580 location admin: show/ hide fields based on location type 2021-10-22 11:27:52 +02:00
nobohan
e24fd8aff0 location admin: improve admin crud for location 2021-10-22 10:01:24 +02:00
nobohan
e9322e61d4 location admin: admin crud for location 2021-10-21 21:39:32 +02:00
c38196006c confidential component created and added to personRenderBox on resourceItem and participationItem as demo. bug: eye icon only appears when clicking on the vue devtools extension in firefox? 2021-10-21 16:52:27 +02:00
a754bc0abe blur added to requestor in twig template 2021-10-21 16:52:27 +02:00
f09329daee blur logic implemented on view.html.twig of Person by means of example 2021-10-21 16:52:27 +02:00
b40ed48776 restructuring files to /module 2021-10-21 16:52:27 +02:00
97cf6e52ac first commit 2021-10-21 16:52:27 +02:00
nobohan
92843677f9 location admin: add admin crud for location type 2021-10-21 16:30:37 +02:00
nobohan
e06a98e70a user menu: remove useless commented lines (user menus are implemented in their own chill bundles 2021-10-21 13:48:42 +02:00
nobohan
821480c06f calendar: add a menu user entry 2021-10-21 13:47:56 +02:00
nobohan
db67ed3194 rdv->calendar: add location 2021-10-20 22:04:20 +02:00
nobohan
8962c1c05f add fixture for location type 2021-10-20 21:46:16 +02:00
dded4fb804 rename method 2021-10-20 20:50:27 +02:00
02ca9add52 refactor naming ReferralsAvailable => referralSuggestion 2021-10-20 20:49:44 +02:00
3f138dc152 show users as suggestions, not in constrained list 2021-10-20 19:59:08 +02:00
nobohan
d1e2257db6 fix merge request conflict for improve address 2021-10-20 15:52:22 +02:00
0a058bad82 update list of referrers when loading and updating some parts of the course 2021-10-20 15:03:42 +02:00
4f21c7f219 simplifiy filter order 2021-10-20 13:11:02 +02:00
c8762d2bc2 list referral for an accompanying period 2021-10-20 13:10:28 +02:00
94c91d5825 simplifiy filter order 2021-10-20 13:09:38 +02:00
2227d5c66f translation fixed in master vendee branch 2021-10-18 16:56:33 +02:00
47f7837ab2 Merge branch 'issue97_rename_field' into 'master'
utilisateur field label changed

See merge request Chill-Projet/chill-bundles!177
2021-10-18 14:48:48 +00:00
f889d43f6c update changelog 2021-10-18 16:47:16 +02:00
eecb11436e field label for duration of activity 2021-10-18 15:33:26 +02:00
220dafeb99 utilisateur field label changed 2021-10-18 14:50:34 +02:00
8be11314c3 Merge branch 'master' into HEAD 2021-10-18 13:49:00 +02:00
f89e92e88b Merge branch 'features/improve-admin-user-list' 2021-10-18 13:35:32 +02:00
acdb4fdd36 fixes in translation form admin 2021-10-18 13:34:59 +02:00
b73332c4a3 show errors in ChillCollectionType 2021-10-18 13:33:41 +02:00
8fb5a1b5e8 fixes in translation form admin 2021-10-18 13:33:19 +02:00
5d494221d2 confidential component created and added to personRenderBox on resourceItem and participationItem as demo. bug: eye icon only appears when clicking on the vue devtools extension in firefox? 2021-10-18 13:11:14 +02:00
nobohan
fcc8f67094 Merge branch 'master' of gitlab.com:Chill-Projet/chill-bundles 2021-10-18 11:24:29 +02:00
nobohan
99b99de9be update CHANGELOG 2021-10-18 11:23:14 +02:00
nobohan
31fd9cee57 update CHANGELOG 2021-10-18 11:21:13 +02:00
809eb9643e Merge branch 'optimize_address' into 'master'
Address: Optimize address

See merge request Chill-Projet/chill-bundles!170
2021-10-18 09:17:05 +00:00
89b0b94d22 Merge branch 'feature/form-move-household-with-checkboxes' into 'master'
rewrite form move household

See merge request Chill-Projet/chill-bundles!159
2021-10-18 09:14:28 +00:00
e6e5bfee4f update changelog [ci-skip] 2021-10-15 17:46:00 +02:00
9cbac89cae handle leaving household 2021-10-15 17:43:28 +02:00
8f361567ff form as carrousel finalized 2021-10-15 16:40:31 +02:00
8c87eaa46f upgrading changelog 2021-10-15 15:46:04 +02:00
6565e3f8e3 fix invisible selected item in multiselect 2021-10-15 15:37:16 +02:00
6876c23adb adapting vue_calendar to use Location 2021-10-15 15:28:33 +02:00
d86307327c fix error in LocationApiController customizeQuery 2021-10-15 14:12:06 +02:00
0e18a3ada9 adding location hidden field in Calendar formType 2021-10-15 13:13:00 +02:00
4677fadf6f adding activity location in show template + translations 2021-10-15 13:11:14 +02:00
3e4cb41f7a vue_activity Location i18n translations 2021-10-15 12:49:15 +02:00
ada9efc75d filter list of locations on backend side (GET location endpoint) 2021-10-15 12:01:57 +02:00
d0dd99db9a fix Location POST endpoint and saveNewLocation event method in vue_activity Location 2021-10-15 11:25:18 +02:00
e6845326d7 vue_activity location: add NewLocation fields, submit activity form with hidden field (+) 2021-10-15 09:09:47 +02:00
61488e9876 WIP test filtering elements on household [household editor] 2021-10-14 16:05:19 +02:00
a4af30e542 update changelog 2021-10-14 16:05:17 +02:00
58a8949cac download household on same address 2021-10-14 16:03:48 +02:00
c179649c56 load suggestion WIP 2021-10-14 16:03:48 +02:00
05b2b2f9b8 Link between address and reference, and api endpoint to find household
by address reference

* add a one-to-many link between address and address reference;
* update AddAddress.vue to add information on picked address reference;
* add an HouseholdACLAwareRepository, with a method to find household by
current address reference
* add an endpoint to retrieve household by address reference
* + tests
2021-10-14 16:03:48 +02:00
6430de94a7 try to fix button in controller issue 2021-10-14 16:03:48 +02:00
62d3bf8742 do not allow to update address from an existing household 2021-10-14 16:03:48 +02:00
0437e00dcd suggest only temporary addresses 2021-10-14 16:03:48 +02:00
dc7bcb5233 update changelog 2021-10-14 16:03:06 +02:00
b3bd4a5b49 Merge branch 'fix-tests/fix-2021-10-14' into 'master'
Fix tests with capitalization

See merge request Chill-Projet/chill-bundles!175
2021-10-14 14:01:18 +00:00
4f940b44ad Fix tests with capitalization 2021-10-14 14:01:18 +00:00
4d4662a634 adding endpoint for LocationType. fetch types and add form fields. 2021-10-13 19:31:48 +02:00
b418d13190 make somes changes on model: to manage isVisible field option + others 2021-10-13 15:47:48 +02:00
48f3c440a2 adding an API GET Location endpoint, fetch locations and list them in vue multiselect 2021-10-13 14:22:53 +02:00
342c462ed7 prepare vue Location component 2021-10-13 12:02:45 +02:00
49b1b6f413 vue_activity: add a Location sub-component, teleported in form 2021-10-13 09:56:29 +02:00
7c21818f00 vue_activity: removing v-model in a multiselect (try to fix warning in console) 2021-10-13 09:54:50 +02:00
2d0895b83d calendar: remove useless bootstrap col classes 2021-10-13 09:24:15 +02:00
e570f5c28e adding Entities Location and LocationType (for activity/calendar) + doctrine migration 2021-10-12 17:38:09 +02:00
nobohan
210c199a35 CHANGELOG: order addresses 2021-10-12 15:10:09 +02:00
nobohan
e4a05a1812 Address: order address in back-end 2021-10-12 15:09:34 +02:00
82ae300bd9 vue accourse banner: change "by" translation 2021-10-12 13:12:45 +02:00
85538f74b7 vue person renderbox, fix title 2021-10-12 13:12:45 +02:00
f1773997ce fix/adapt gender translation 2021-10-12 13:12:30 +02:00
ae7774ac39 init household filiation page with hello world visjs graph 2021-10-12 09:55:47 +02:00
nobohan
62c0410bf5 address: sort cities by code and then by name + improve city display 2021-10-11 16:16:49 +02:00
nobohan
f7954d5159 address: sort address by street and street number 2021-10-11 16:05:03 +02:00
nobohan
30fcdfd1f6 addresses: remove duplicate in postal codes 2021-10-11 14:15:59 +02:00
78b651bdc4 blur added to requestor in twig template 2021-10-08 23:44:06 +02:00
487103375d blur logic implemented on view.html.twig of Person by means of example 2021-10-08 22:21:40 +02:00
nobohan
acbd6e761a address: zoom on postal code on select city 2021-10-08 15:51:51 +02:00
nobohan
cae3defedb address: zoom to postal code 2021-10-08 14:50:09 +02:00
nobohan
78f66d4f14 Address: Assign origin = 3 for postalCode created by users 2021-10-08 12:36:48 +02:00
1ffff1f72c restructuring files to /module 2021-10-07 17:10:52 +02:00
1ded5b7c01 first commit 2021-10-07 14:18:25 +02:00
461b96ea37 duplicate templates deleted 2021-10-01 11:32:46 +02:00
fc237db98a fix: wrong template rendered for new course task 2021-10-01 11:32:32 +02:00
43daab1f7b transition button added to listitems of course tasks 2021-10-01 11:32:05 +02:00
85e8fe59a4 changes to TaskVoter reinstated, mistake made in conflict resolvement 2021-10-01 11:18:10 +02:00
262fefa92f access granted condition lifted temporarily to show the 'add new task' button on index page for Person 2021-10-01 10:52:05 +02:00
1403ee2ba5 redirect after submit bug fixed for edit and delete when coming from show.html.twig 2021-10-01 10:49:55 +02:00
548247188f temporarily lifted scope validation, currently no scopes in select list to be selected 2021-10-01 10:49:07 +02:00
6a34046e93 comments deleted, notations adjusted, ... 2021-10-01 10:47:32 +02:00
88b8ff86d1 reorganize templates for a better structure 2021-10-01 10:45:04 +02:00
cc258ba164 templates added for transition of course task and taskcontroller adapted to show correct template 2021-09-30 14:24:17 +02:00
5d69e48787 more conformity between URL's single-task 2021-09-30 14:22:20 +02:00
cb4059e5c3 comment out use of voter for menu entry, new way of handling rights? 2021-09-28 14:37:27 +02:00
8411c909ff notation modifications 2021-09-28 12:55:46 +02:00
41fc41b1da migration namespace adjusted 2021-09-28 12:55:46 +02:00
cb5b45cbe8 autowire and configure MenuBuilder 2021-09-28 12:55:46 +02:00
4c47a35457 Fix SingleTaskListType
accompanyingCourse also defined as a form option
2021-09-28 12:55:46 +02:00
34dd35f2e2 Changed name of PersonMenuBuilder
More general name since it also contains the AccompanyingPeriod task menu entry now.
2021-09-28 12:55:46 +02:00
6e3ce06fcf new/show/edit/delete/list functionality added for accompanyingperiod task 2021-09-28 12:55:46 +02:00
537518b66f controller and templates adapted to display list of accompanying period tasks + detailpage of task 2021-09-28 12:53:24 +02:00
4ad9714e8b Menu entry added in PersonMenuBuilder of taskbundle. Removed from menubuilder in Personbundle. Rename file, PersonMenuBuilder to MenuBuilder? 2021-09-28 12:53:23 +02:00
5a936cd20b templates + controller further adapted to work with accompanyingCourse. new and show methods don't work yet due to authorization/voter issues
templates adapted for use with accompanyingCourse tasks also
2021-09-28 12:53:23 +02:00
1fb14834b7 tasks added to accompanyingCourse menu 2021-09-28 12:53:23 +02:00
53fc5b8399 adaptation of newTask() method in singleTaskController 2021-09-28 12:49:38 +02:00
8318458805 relation between task and accompanyingcourse created 2021-09-28 12:49:38 +02:00
7515415888 autowire and configure MenuBuilder 2021-09-17 15:18:48 +02:00
27a52ce166 Fix SingleTaskListType
accompanyingCourse also defined as a form option
2021-09-17 14:53:15 +02:00
17b6f287dc Changed name of PersonMenuBuilder
More general name since it also contains the AccompanyingPeriod task menu entry now.
2021-09-17 14:49:43 +02:00
01ae50aca7 new/show/edit/delete/list functionality added for accompanyingperiod task 2021-09-17 14:48:29 +02:00
a156bd0863 controller and templates adapted to display list of accompanying period tasks + detailpage of task 2021-09-16 15:55:09 +02:00
b1dbd8b011 Menu entry added in PersonMenuBuilder of taskbundle. Removed from menubuilder in Personbundle. Rename file, PersonMenuBuilder to MenuBuilder? 2021-09-15 11:13:09 +02:00
b28b4e5fba templates + controller further adapted to work with accompanyingCourse. new and show methods don't work yet due to authorization/voter issues
templates adapted for use with accompanyingCourse tasks also
2021-09-10 15:19:59 +02:00
ead96f3836 tasks added to accompanyingCourse menu 2021-09-10 14:57:41 +02:00
27077c9d96 adaptation of newTask() method in singleTaskController 2021-09-09 18:21:41 +02:00
8a38712525 relation between task and accompanyingcourse created 2021-09-09 17:43:35 +02:00
346 changed files with 10028 additions and 3551 deletions

View File

@@ -15,7 +15,9 @@ before_script:
- curl -sS https://getcomposer.org/installer | php
- php -d memory_limit=2G composer.phar install
- php tests/app/bin/console doctrine:migrations:migrate -n
- php -d memory_limit=2G tests/app/bin/console doctrine:fixtures:load -n
- php -d memory_limit=2G tests/app/bin/console cache:clear --env=dev
- php -d memory_limit=3G tests/app/bin/console doctrine:fixtures:load -n
- php -d memory_limit=2G tests/app/bin/console cache:clear --env=test
- echo "before_script finished"
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service

View File

@@ -0,0 +1,24 @@
# Description of changes
<!--
describe here the change of your MR. It can be either a text, or a bullet list
for changes
-->
# Issues related
<!--
list the issues related to this MR.
It may be client issues, or dev issues
-->
* ...
* ...
# Tests
<!-- Describe tests if any, or why no tests -->

View File

@@ -10,15 +10,68 @@ and this project adheres to
## Unreleased
* [3party]: french translation of contact and company
* [3party]: show parent in list
* [3party]: change color for badge "child"
<!-- write down unreleased development here -->
## Test releases
### Test release 2021-11-08
* [person]: Add civility to the person
* [person]: Various improvements on the edit person form
* [person]: Set available_languages and available_countries as parameters for use in the edit person form
* [activity] Bugfix: documents can now be added to an activity.
* [tasks] improve tasks with filter order
* [tasks] refactor singleControllerTasks: limit the number of conditions from the context
* [validations] validation of accompanying period added: no duplicate participations or resources (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/60).
* [renderbox] If gender of person is not defined, no icon is displayed instead of neuter-icon (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/129).
* [confidential information] module added to blur confidential information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/248).
* refactor `AuthorizationHelper` and `UserACLAwareRepository` to fix constructor, and separate logic for parent role helper into `ParentRoleHelper`
* [main]: filter location and locationType in backend: exclude NULL names, only active and availableToUsers
* [activity]: perform client-side validation & show/hide fields in the "new location" modal
* [person]: normalize person with CenterResolverDispatcher and handle case where center is null or multiple in PersonRenderBox
* [docstore] voter for PersonDocument and AccompanyingCourseDocument on the 2.0 way (using VoterHelperFactory)
* [docstore] add authorization check inside controller and menu
* [activity]: fix inheritance for role `ACTIVITY FULL` and add missing acl in menu
* [person] show current address in search results
* [person] show alt names in search results
* [admin]: links to activity admin section added again.
* [household]: endDate field deleted from household edit form.
* [household]: View accompanying periods of current and old household members.
* [tasks]: different layout for task list / my tasks, and fix link to tasks in alert or in warning
* [admin]: links to activity admin section added again.
* [household]: household addresses ordered by ValidFrom date and by id to show the last created address on top.
* [socialWorkAction]: display of social issue and parent issues + banner context added.
* [DBAL dependencies] Upgrade to DBAL 3.1
* [person]: double parentheses removed around age in banner + whitespace
### Test release 2021-10-27
* [person]: delete double actions buttons on search person page
* [person]: accompanying course work: remove creation date display the list of work + handle case when end date is null
* [main]: Add new pages with a menu for managing location and location type in the admin
* [main]: Add some fixtures for location type
* [calendar]: Pass the location when transforming a calendar item (rdv) into an activity
* [calendar]: Add a user menu for "my calendar"
### Test release 2021-10-18
* [3party]: french translation of contact and company
* [3party]: show parent in list
* [3party]: change color for badge "child"
* [3party]: fix address creation
* [household members editor] finalisation of editor
* [AccompanyingCourse banner]: replace translation referrer (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/70)
* [Location]: add location system in activity and RV (calendar). User can choose in location list or create a new location.
### Test release 2021-10-11
* Address: zoom on postal code geometry + fix origin of manually entered postal code
* in the Address vue component, order the postal code and street address by alphabetic and numeric order
* add 3 new fields to PostalCode and adapt postal code command and fixtures
* [Aside activity] Fixes for aside activity
@@ -38,10 +91,14 @@ and this project adheres to
* [FilterOrder]: add development kit for generating filter and ordering in list
* [Capitalization of names] person names are capitalized on creation, on prePersist event
* [On-The-Fly] modale works for showing, editing and creating person or thirdparty ;
* [AccompanyingCourse Resume page] associated persons list, can see household when hover, and with show on-the-fly modale when clicking person ;
### test release 2021-10-04
* [Household editor][UI] Update how household suggestion and addresses are picked;
See https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/80
* [AddAddress] Handle address suggestion;
* [CenterType][Create a person] when overriding the ACL rules, allow to show a PickCenterType
when no centers are reachable by the default ACL.
@@ -60,8 +117,31 @@ and this project adheres to
https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/37
https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/221
* [On-The-Fly] modale works for showing, editing and creating person or thirdparty ;
* [AccompanyingCourse Resume page] associated persons list, can see household when hover, and with show on-the-fly modale when clicking person ;
* [Household editor] suggest only temporarily addresses;
See https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/82
* On-The-Fly modale works for showing, editing and creating person and thirdparty ;
* AccompanyingCourse Resume page: list associated persons by household, see household when hover, and show on-the-fly modale when clicking on person ;
* [AddAddress] Handle address suggestion;
* [AddAddress][Entity address]: add a link between address and address reference;
* [Household editor] suggest household by comparing the temporary addresses from courses;
## Test release yyyy-mm-dd
See https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/81
* On-The-Fly modale works for showing, editing and creating person and thirdparty
## Test released
<!--
Coming soon...
DO NOT ADD unreleased items here. Add them under "Unreleased" title
### Test release yyyy-mm-dd
-->
## Stable releases
No stable releases for v2+

View File

@@ -54,6 +54,9 @@
"doctrine/doctrine-fixtures-bundle": "^3.3",
"fakerphp/faker": "^1.13",
"nelmio/alice": "^3.8",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^7.0",
"symfony/debug-bundle": "^5.1",
"symfony/dotenv": "^5.1",

1542
phpstan-baseline.neon Normal file

File diff suppressed because it is too large Load Diff

21
phpstan.neon.dist Normal file
View File

@@ -0,0 +1,21 @@
parameters:
level: 1
paths:
- src/
excludePaths:
- src/Bundle/*/Tests/*
- src/Bundle/*/Test/*
- src/Bundle/*/config/*
- src/Bundle/*/migrations/*
- src/Bundle/*/translations/*
- src/Bundle/*/Resources/*
- src/Bundle/*/src/Tests/*
- src/Bundle/*/src/Test/*
- src/Bundle/*/src/config/*
- src/Bundle/*/src/migrations/*
- src/Bundle/*/src/translations/*
- src/Bundle/*/src/Resources/*
includes:
- phpstan-baseline.neon

View File

@@ -242,6 +242,11 @@ class ActivityController extends AbstractController
}
}
if (array_key_exists('location', $activityData)) {
$location = $em->getRepository(\Chill\MainBundle\Entity\Location::class)->find($activityData['location']);
$entity->setLocation($location);
}
if (array_key_exists('comment', $activityData)) {
$comment = new CommentEmbeddable();
$comment->setComment($activityData['comment']);

View File

@@ -141,7 +141,6 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
$ref = 'activity_'.$person->getFullnameCanonical();
for($i = 0; $i < $activityNbr; $i ++) {
print "Creating an activity type for : ".$person." (ref: ".$ref.") \n";
$activity = $this->newRandomActivity($person);
$manager->persist($activity);
}

View File

@@ -87,7 +87,9 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
ActivityVoter::UPDATE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::CREATE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::DELETE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::SEE_DETAILS => array(ActivityVoter::SEE)
ActivityVoter::SEE_DETAILS => array(ActivityVoter::SEE),
ActivityVoter::FULL => [ActivityVoter::CREATE, ActivityVoter::DELETE,
ActivityVoter::UPDATE],
)
));
}

View File

@@ -23,6 +23,7 @@ namespace Chill\ActivityBundle\Entity;
use Chill\DocStoreBundle\Entity\Document;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\Location;
use Chill\PersonBundle\AccompanyingPeriod\SocialIssueConsistency\AccompanyingPeriodLinkedWithSocialIssuesEntityInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
@@ -157,7 +158,7 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer
private ?Collection $thirdParties = null;
/**
* @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject")
* @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject", cascade={"persist"})
*/
private Collection $documents;
@@ -177,6 +178,13 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer
*/
private string $sentReceived = '';
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Location")
* @groups({"read"})
*/
private ?Location $location = null;
public function __construct()
{
$this->reasons = new ArrayCollection();
@@ -555,4 +563,22 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer
return $this;
}
/**
* @return Location|null
*/
public function getLocation(): ?Location
{
return $this->location;
}
/**
* @param Location|null $location
* @return Activity
*/
public function setLocation(?Location $location): Activity
{
$this->location = $location;
return $this;
}
}

View File

@@ -1,19 +1,19 @@
<?php
/*
*
*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -44,7 +44,7 @@ class ActivityReason
/**
* @var array
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
@@ -108,7 +108,7 @@ class ActivityReason
return $this->name;
}
}
/**
* Set category of the reason. If you set to the reason an inactive
* category, the reason will become inactive
@@ -121,7 +121,7 @@ class ActivityReason
if($this->category !== $category && ! $category->getActive()) {
$this->setActive(False);
}
$this->category = $category;
return $this;

View File

@@ -2,17 +2,17 @@
/*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -43,7 +43,7 @@ class ActivityReasonCategory
/**
* @var string
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
@@ -52,7 +52,7 @@ class ActivityReasonCategory
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* Array of ActivityReason
* @var ArrayCollection
@@ -61,7 +61,7 @@ class ActivityReasonCategory
* mappedBy="category")
*/
private $reasons;
/**
* ActivityReasonCategory constructor.
*/
@@ -69,7 +69,7 @@ class ActivityReasonCategory
{
$this->reasons = new ArrayCollection();
}
/**
* @return string
*/
@@ -139,9 +139,9 @@ class ActivityReasonCategory
$reason->setActive($active);
}
}
$this->active = $active;
return $this;
}

View File

@@ -44,7 +44,7 @@ class ActivityType
private ?int $id;
/**
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private array $name = [];
@@ -248,6 +248,16 @@ class ActivityType
*/
private string $socialActionsLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $locationVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $locationLabel = '';
/**
* @ORM\Column(type="float", options={"default"="0.0"})
*/
@@ -820,4 +830,29 @@ class ActivityType
return $this;
}
public function getLocationVisible(): ?int
{
return $this->locationVisible;
}
public function setLocationVisible(int $locationVisible): self
{
$this->locationVisible = $locationVisible;
return $this;
}
public function getLocationLabel(): ?string
{
return $this->locationLabel;
}
public function setLocationLabel(string $locationLabel): self
{
$this->locationLabel = $locationLabel;
return $this;
}
}

View File

@@ -40,7 +40,7 @@ class ActivityTypeCategory
private ?int $id;
/**
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private array $name = [];

View File

@@ -29,27 +29,27 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
/**
*
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityTypeAggregator implements AggregatorInterface
{
/**
*
* @var EntityRepository
*/
protected $typeRepository;
/**
*
* @var TranslatableStringHelper
*/
protected $stringHelper;
const KEY = 'activity_type_aggregator';
public function __construct(
EntityRepository $typeRepository,
TranslatableStringHelper $stringHelper
@@ -57,19 +57,19 @@ class ActivityTypeAggregator implements AggregatorInterface
$this->typeRepository = $typeRepository;
$this->stringHelper = $stringHelper;
}
public function alterQuery(QueryBuilder $qb, $data)
{
// add select element
// add select element
$qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY));
// add the "group by" part
$groupBy = $qb->addGroupBy(self::KEY);
}
/**
* Check if a join between Activity and another alias
*
*
* @param Join[] $joins
* @param string $alias the alias to search for
* @return boolean
@@ -81,7 +81,7 @@ class ActivityTypeAggregator implements AggregatorInterface
return true;
}
}
return false;
}
@@ -99,18 +99,18 @@ class ActivityTypeAggregator implements AggregatorInterface
{
return "Aggregate by activity type";
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function getLabels($key, array $values, $data)
public function getLabels($key, array $values, $data): \Closure
{
// for performance reason, we load data from db only once
$this->typeRepository->findBy(array('id' => $values));
return function($value) use ($data) {
return function($value): string {
if ($value === '_header') {
return 'Activity type';
}
@@ -120,12 +120,11 @@ class ActivityTypeAggregator implements AggregatorInterface
return $this->stringHelper->localize($t->getName());
};
}
public function getQueryKeys($data)
public function getQueryKeys($data): array
{
return array(self::KEY);
return [self::KEY];
}
}

View File

@@ -6,6 +6,7 @@ use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityPresence;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\DocStoreBundle\Form\StoredObjectType;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Form\Type\ChillCollectionType;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\PersonBundle\Entity\Person;
@@ -222,7 +223,7 @@ class ActivityType extends AbstractType
if ($activityType->isVisible('comment')) {
$builder->add('comment', CommentType::class, [
'label' => empty($activityType->getLabel('comment'))
'label' => empty($activityType->getLabel('comment'))
? 'activity.comment' : $activityType->getLabel('comment'),
'required' => $activityType->isRequired('comment'),
]);
@@ -302,6 +303,23 @@ class ActivityType extends AbstractType
;
}
if ($activityType->isVisible('location')) {
$builder->add('location', HiddenType::class)
->get('location')
->addModelTransformer(new CallbackTransformer(
function (?Location $location): string {
if (null === $location) {
return '';
}
return $location->getId();
},
function (?string $id): ?Location {
return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]);
}
))
;
}
if ($activityType->isVisible('emergency')) {
$builder->add('emergency', CheckboxType::class, [
'label' => $activityType->getLabel('emergency'),

View File

@@ -71,7 +71,7 @@ class TranslatableActivityType extends AbstractType
if ($options['active_only'] === true) {
$qb->where($qb->expr()->eq('at.active', ':active'));
$qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN);
$qb->setParameter('active', true, \Doctrine\DBAL\Types\Types::BOOLEAN);
}
}

View File

@@ -2,29 +2,27 @@
namespace Chill\ActivityBundle\Menu;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
{
protected TokenStorageInterface $tokenStorage;
protected AuthorizationHelper $authorizationHelper;
protected TranslatorInterface $translator;
protected Security $security;
public function __construct(
TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper,
Security $security,
TranslatorInterface $translator
) {
$this->security = $security;
$this->translator = $translator;
$this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage;
}
public static function getMenuIds(): array
{
@@ -35,7 +33,8 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
{
$period = $parameters['accompanyingCourse'];
if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()) {
if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()
&& $this->security->isGranted(ActivityVoter::SEE, $period)) {
$menu->addChild($this->translator->trans('Activity'), [
'route' => 'chill_activity_activity_list',
'routeParameters' => [

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Security;
final class AdminMenuBuilder implements LocalMenuBuilderInterface
{
private Security $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public static function getMenuIds(): array
{
return ['admin_index', 'admin_section', 'admin_activity'];
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
if (!$this->security->isGranted('ROLE_ADMIN')) {
return;
}
if (in_array($menuId, ['admin_index', 'admin_section'])) {
$menu->addChild('Activities', [
'route' => 'chill_admin_activity_index'
])
->setExtras([
'order' => 2000,
'explain' => "Activity configuration"
]);
} else {
$menu
->addChild('Activities', [
'route' => 'chill_admin_activity_index'
])
->setExtras([
'order' => '60'
]);
}
}
}

View File

@@ -1,17 +1,20 @@
<template>
<concerned-groups></concerned-groups>
<social-issues-acc></social-issues-acc>
<location></location>
</template>
<script>
import ConcernedGroups from './components/ConcernedGroups.vue';
import SocialIssuesAcc from './components/SocialIssuesAcc.vue';
import Location from './components/Location.vue';
export default {
name: "App",
components: {
ConcernedGroups,
SocialIssuesAcc
SocialIssuesAcc,
Location
}
}
</script>

View File

@@ -3,16 +3,61 @@ import { getSocialIssues } from 'ChillPersonAssets/vuejs/AccompanyingCourse/api.
/*
* Load socialActions by socialIssue (id)
*/
const getSocialActionByIssue = (id) => {
const getSocialActionByIssue = (id) => {
const url = `/api/1.0/person/social/social-action/by-social-issue/${id}.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw Error('Error with request resource response');
});
};
/*
* Load Locations
*/
const getLocations = () => {
const url = `/api/1.0/main/location.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
/*
* Load Location Types
*/
const getLocationTypes = () => {
const url = `/api/1.0/main/location-type.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
/*
* Post a Location
*/
const postLocation = (body) => {
const url = `/api/1.0/main/location.json`;
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(body)
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
export {
getSocialIssues,
getSocialActionByIssue
getSocialActionByIssue,
getLocations,
getLocationTypes,
postLocation
};

View File

@@ -73,9 +73,12 @@ export default {
addPersons: {
key: 'activity',
options: {
type: ['person', 'thirdparty', 'user'], // TODO add 'user'
type: ['person', 'thirdparty', 'user'],
priority: null,
uniq: false,
button: {
size: 'btn-sm'
}
}
}
}

View File

@@ -0,0 +1,74 @@
<template>
<teleport to="#location">
<div class="mb-3 row">
<label class="col-form-label col-sm-4">
{{ $t('activity.location') }}
</label>
<div class="col-sm-8">
<VueMultiselect
name="selectLocation"
id="selectLocation"
label="name"
track-by="id"
open-direction="top"
:multiple="false"
:searchable="true"
:placeholder="$t('activity.choose_location')"
:custom-label="customLabel"
:options="locations"
v-model="location">
</VueMultiselect>
<new-location v-bind:locations="locations"></new-location>
</div>
</div>
</teleport>
</template>
<script>
import { mapState } from "vuex";
import VueMultiselect from 'vue-multiselect';
import NewLocation from './Location/NewLocation.vue';
import { getLocations } from '../api.js';
export default {
name: "Location",
components: {
NewLocation,
VueMultiselect
},
data() {
return {
locations: []
}
},
computed: {
...mapState(['activity']),
location: {
get() {
return this.activity.location;
},
set(value) {
this.$store.dispatch('updateLocation', value);
}
}
},
mounted() {
this.getLocationsList();
},
methods: {
getLocationsList() {
getLocations().then(response => new Promise(resolve => {
console.log('getLocations', response);
this.locations = response.results;
resolve();
}))
},
customLabel(value) {
return `${value.locationType.title.fr} ${value.name ? value.name : ''}`;
}
}
}
</script>

View File

@@ -0,0 +1,271 @@
<template>
<div>
<ul class="record_actions">
<li>
<a class="btn btn-sm btn-create" @click="openModal">
{{ $t('activity.create_new_location') }}
</a>
</li>
</ul>
<teleport to="body">
<modal v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false">
<template v-slot:header>
<h3 class="modal-title">{{ $t('activity.create_new_location') }}</h3>
</template>
<template v-slot:body>
<form>
<div class="form-floating mb-3">
<p v-if="errors.length">
<b>{{ $t('activity.errors') }}</b>
<ul>
<li v-for="error in errors" :key="error">{{ error }}</li>
</ul>
</p>
</div>
<div class="form-floating mb-3">
<select class="form-select form-select-lg" id="type" required v-model="selectType">
<option selected disabled value="">{{ $t('activity.choose_location_type') }}</option>
<option v-for="t in locationTypes" :value="t" :key="t.id">
{{ t.title.fr }}
</option>
</select>
<label>{{ $t('activity.location_fields.type') }}</label>
</div>
<div class="form-floating mb-3">
<input class="form-control form-control-lg" id="name" v-model="inputName" placeholder />
<label for="name">{{ $t('activity.location_fields.name') }}</label>
</div>
<add-address
:context="addAddress.context"
:options="addAddress.options"
:addressChangedCallback="submitNewAddress"
v-if="showAddAddress"
ref="addAddress">
</add-address>
<div class="form-floating mb-3" v-if="showContactData">
<input class="form-control form-control-lg" id="phonenumber1" v-model="inputPhonenumber1" placeholder />
<label for="phonenumber1">{{ $t('activity.location_fields.phonenumber1') }}</label>
</div>
<div class="form-floating mb-3" v-if="hasPhonenumber1">
<input class="form-control form-control-lg" id="phonenumber2" v-model="inputPhonenumber2" placeholder />
<label for="phonenumber2">{{ $t('activity.location_fields.phonenumber2') }}</label>
</div>
<div class="form-floating mb-3" v-if="showContactData">
<input class="form-control form-control-lg" id="email" v-model="inputEmail" placeholder />
<label for="email">{{ $t('activity.location_fields.email') }}</label>
</div>
</form>
</template>
<template v-slot:footer>
<button class="btn btn-save"
@click.prevent="saveNewLocation"
>
{{ $t('action.save') }}
</button>
</template>
</modal>
</teleport>
</div>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue";
import { mapState } from "vuex";
import { getLocationTypes, postLocation } from "../../api";
export default {
name: "NewLocation",
components: {
Modal,
AddAddress,
},
props: ['locations'],
data() {
return {
errors: [],
selected: {
type: null,
name: null,
addressId: null,
phonenumber1: null,
phonenumber2: null,
email: null,
},
locationTypes: [],
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl"
},
addAddress: {
options: {
button: {
text: { create: 'activity.create_address', edit: 'activity.edit_address' },
size: 'btn-sm'
},
title: { create: 'activity.create_address', edit: 'activity.edit_address' },
},
context: {
target: { //name, id
},
edit: false,
addressId: null
}
}
}
},
computed: {
...mapState(['activity']),
selectType: {
get() {
return this.selected.type;
},
set(value) {
this.selected.type = value;
}
},
inputName: {
get() {
return this.selected.name;
},
set(value) {
this.selected.name = value;
}
},
inputEmail: {
get() {
return this.selected.email;
},
set(value) {
this.selected.email = value;
}
},
inputPhonenumber1: {
get() {
return this.selected.phonenumber1;
},
set(value) {
this.selected.phonenumber1 = value;
}
},
inputPhonenumber2: {
get() {
return this.selected.phonenumber2;
},
set(value) {
this.selected.phonenumber2 = value;
}
},
hasPhonenumber1() {
return this.selected.phonenumber1 !== null && this.selected.phonenumber1 !== "";
},
showAddAddress() {
let cond = false;
if (this.selected.type) {
if (this.selected.type.addressRequired !== 'never') {
cond = true;
}
}
return cond;
},
showContactData() {
let cond = false;
if (this.selected.type) {
if (this.selected.type.contactData !== 'never') {
cond = true;
}
}
return cond;
},
},
mounted() {
this.getLocationTypesList();
},
methods: {
checkForm() {
let cond = true;
this.errors = [];
if (!this.selected.type) {
this.errors.push('Type de localisation requis');
cond = false;
} else {
if (this.selected.type.addressRequired === 'required' && !this.selected.addressId) {
this.errors.push('Adresse requise');
cond = false;
}
if (this.selected.type.contactData === 'required' && !this.selected.phonenumber1) {
this.errors.push('Numéro de téléphone requis');
cond = false;
}
if (this.selected.type.contactData === 'required' && !this.selected.email) {
this.errors.push('Adresse email requise');
cond = false;
}
}
return cond;
},
getLocationTypesList() {
getLocationTypes().then(response => new Promise(resolve => {
console.log('getLocationTypes', response);
this.locationTypes = response.results.filter(t => t.availableForUsers === true);
resolve();
}))
},
openModal() {
this.modal.showModal = true;
},
saveNewLocation() {
if (this.checkForm()) {
console.log('saveNewLocation', this.selected);
let body = {
type: 'location',
name: this.selected.name,
locationType: {
id: this.selected.type.id,
type: 'location-type'
},
phonenumber1: this.selected.phonenumber1,
phonenumber2: this.selected.phonenumber2,
email: this.selected.email,
};
if (this.selected.addressId) {
body = Object.assign(body, {
address: {
id: this.selected.addressId
}
});
}
postLocation(body)
.then(
location => new Promise(resolve => {
console.log('postLocation', location);
this.locations.push(location);
this.$store.dispatch('updateLocation', location);
resolve();
this.modal.showModal = false;
})
).catch(
err => {
this.errors.push(err.message);
}
);
};
},
submitNewAddress(payload) {
console.log('submitNewAddress', payload);
this.selected.addressId = payload.addressId;
this.addAddress.context.addressId = payload.addressId;
this.addAddress.context.edit = true;
}
}
}
</script>

View File

@@ -1,12 +1,12 @@
<template>
<teleport to="#social-issues-acc">
<div class="mb-3 row">
<div class="col-4">
<label class="col-form-label">{{ $t('activity.social_issues') }}</label>
</div>
<div class="col-8">
<check-social-issue
v-for="issue in socialIssuesList"
v-bind:key="issue.id"
@@ -14,7 +14,7 @@
v-bind:selection="socialIssuesSelected"
@updateSelected="updateIssuesSelected">
</check-social-issue>
<div class="my-3">
<VueMultiselect
name="otherIssues"
@@ -28,16 +28,15 @@
v-bind:taggable="false"
v-bind:multiple="false"
v-bind:searchable="true"
v-bind:allow-empty="true"
v-bind:allow-empty="true"
v-bind:show-labels="false"
v-bind:loading="issueIsLoading"
v-bind:placeholder="$t('activity.choose_other_social_issue')"
v-bind:options="socialIssuesOther"
v-model="value"
@select="addIssueInList">
</VueMultiselect>
</div>
</div>
</div>
@@ -46,11 +45,11 @@
<label class="col-form-label">{{ $t('activity.social_actions') }}</label>
</div>
<div class="col-8">
<div v-if="actionIsLoading === true">
<i class="chill-green fa fa-circle-o-notch fa-spin fa-lg"></i>
</div>
<check-social-action
v-if="socialIssuesSelected.length || socialActionsSelected.length"
v-for="action in socialActionsList"
@@ -59,19 +58,18 @@
v-bind:selection="socialActionsSelected"
@updateSelected="updateActionsSelected">
</check-social-action>
<span v-else class="inline-choice chill-no-data-statement mt-3">
{{ $t('activity.select_first_a_social_issue') }}
</span>
</div>
</div>
</teleport>
</template>
<script>
import { readonly } from 'vue';
import VueMultiselect from 'vue-multiselect';
import CheckSocialIssue from './SocialIssuesAcc/CheckSocialIssue.vue';
import CheckSocialAction from './SocialIssuesAcc/CheckSocialAction.vue';
@@ -113,7 +111,7 @@ export default {
this.issueIsLoading = true;
getSocialIssues().then(response => new Promise((resolve, reject) => {
this.$store.commit('updateIssuesOther', response.results);
/* Add in list the issues already associated (if not yet listed)
*/
this.socialIssuesSelected.forEach(issue => {
@@ -121,34 +119,34 @@ export default {
this.$store.commit('addIssueInList', issue);
}
}, this);
/* Remove from multiselect the issues that are not yet in checkbox list
*/
this.socialIssuesList.forEach(issue => {
this.$store.commit('removeIssueInOther', issue);
}, this);
/* Filter issues
*/
this.$store.commit('filterList', 'issues');
/* Add in list the actions already associated (if not yet listed)
*/
this.socialActionsSelected.forEach(action => {
this.$store.commit('addActionInList', action);
}, this);
/* Filter issues
*/
this.$store.commit('filterList', 'actions');
this.issueIsLoading = false;
resolve();
}));
}));
},
methods: {
/* When choosing an issue in multiselect, add it in checkboxes (as selected),
/* When choosing an issue in multiselect, add it in checkboxes (as selected),
remove it from multiselect, and add socialActions concerned
*/
addIssueInList(value) {
@@ -171,30 +169,30 @@ export default {
//console.log('updateActionsSelected', actions);
this.$store.dispatch('updateActionsSelected', actions);
},
/* Add socialActions concerned: after reset, loop on each issue selected
/* Add socialActions concerned: after reset, loop on each issue selected
to get social actions concerned
*/
updateActionsList() {
//console.log('updateActionsList');
this.resetActionsList();
this.socialIssuesSelected.forEach(item => {
this.actionIsLoading = true;
getSocialActionByIssue(item.id)
.then(actions => new Promise((resolve, reject) => {
actions.results.forEach(action => {
this.$store.commit('addActionInList', action);
}, this);
this.$store.commit('filterList', 'actions');
this.actionIsLoading = false;
resolve();
}));
}, this);
},
/* Reset socialActions List: flush list and restore selected actions
/* Reset socialActions List: flush list and restore selected actions
*/
resetActionsList() {
this.$store.commit('resetActionsList');
@@ -207,7 +205,7 @@ export default {
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style lang="scss">
<style lang="scss" scoped>
span.multiselect__single {
display: none !important;
}

View File

@@ -1,14 +1,15 @@
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
const appMessages = {
const activityMessages = {
fr: {
activity: {
//
errors: "Le formulaire contient des erreurs",
social_issues: "Problématiques sociales",
choose_other_social_issue: "Ajouter une autre problématique sociale...",
social_actions: "Actions d'accompagnement",
select_first_a_social_issue: "Sélectionnez d'abord une problématique sociale",
//
add_persons: "Ajouter des personnes concernées",
bloc_persons: "Usagers",
@@ -16,12 +17,28 @@ const appMessages = {
bloc_persons_not_associated: "Tiers non-pro.",
bloc_thirdparty: "Tiers professionnels",
bloc_users: "T(M)S",
//
location: "Localisation",
choose_location: "Choisissez une localisation",
choose_location_type: "Choisissez un type de localisation",
create_new_location: "Créer une nouvelle localisation",
location_fields: {
name: "Nom",
type: "Type",
phonenumber1: "Téléphone",
phonenumber2: "Autre téléphone",
email: "Adresse courriel",
},
create_address: 'Créer une adresse',
edit_address: "Modifier l'adresse"
}
}
}
Object.assign(appMessages.fr, personMessages.fr);
Object.assign(activityMessages.fr, personMessages.fr);
export {
appMessages
activityMessages
};

View File

@@ -1,11 +1,11 @@
import { createApp } from 'vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
import { appMessages } from './i18n'
import { activityMessages } from './i18n'
import store from './store'
import App from './App.vue';
const i18n = _createI18n(appMessages);
const i18n = _createI18n(activityMessages);
const app = createApp({
template: `<app></app>`,

View File

@@ -114,6 +114,10 @@ const store = createStore({
state.activity.users = state.activity.users.filter(user => user !== payload);
break;
};
},
updateLocation(state, value) {
console.log('### mutation: updateLocation', value);
state.activity.location = value;
}
},
actions: {
@@ -173,6 +177,12 @@ const store = createStore({
break;
};
commit('removePersonInvolved', payload);
},
updateLocation({ commit }, value) {
console.log('### action: updateLocation', value);
let hiddenLocation = document.getElementById("chill_activitybundle_activity_location");
hiddenLocation.value = value.id;
commit('updateLocation', value);
}
}
});

View File

@@ -54,7 +54,10 @@
{{ form_row(edit_form.date) }}
{% endif %}
{# TODO .. location #}
{%- if edit_form.location is defined -%}
{{ form_row(edit_form.location) }}
<div id="location"></div>
{% endif %}
{%- if edit_form.durationTime is defined -%}
{{ form_row(edit_form.durationTime) }}

View File

@@ -6,10 +6,10 @@
{% block content %}
<div class="activity-edit">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
</div>
{% endblock %}
@@ -18,10 +18,10 @@
{{ encore_entry_link_tags('mod_async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.activity = {{ activity_json|json_encode|raw }};
window.activity = {{ activity_json|json_encode|raw }};
</script>
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}

View File

@@ -22,10 +22,10 @@
{% block personcontent %}
<div class="activity-edit">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
</div>
{% endblock %}
@@ -33,7 +33,7 @@
{{ encore_entry_link_tags('mod_async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.activity = {{ activity_json|json_encode|raw }};

View File

@@ -55,7 +55,10 @@
{{ form_row(form.date) }}
{% endif %}
{# TODO .. location #}
{%- if form.location is defined -%}
{{ form_row(form.location) }}
<div id="location"></div>
{% endif %}
{%- if form.durationTime is defined -%}
{{ form_row(form.durationTime) }}

View File

@@ -6,10 +6,10 @@
{% block personcontent %}
<div class="activity-new">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:new.html.twig' with {'context': 'person'} %}
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:new.html.twig' with {'context': 'person'} %}
</div>
{% endblock %}
@@ -17,7 +17,7 @@
{{ encore_entry_link_tags('mod_async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.activity = {{ activity_json|json_encode|raw }};

View File

@@ -62,6 +62,21 @@
<dt class="inline">{{ 'Date'|trans }}</dt>
<dd>{{ entity.date|format_date('long') }}</dd>
{% if t.locationVisible %}
<dt class="inline">{{ 'Activity location'|trans }}</dt>
<dd>
{% if entity.location is not null %}
<p>
<span>{{ entity.location.locationType.title|localize_translatable_string }}</span>
{{ entity.location.name }}
</p>
{{ entity.location.address|chill_entity_render_box }}
{% else %}
<span class="chill-no-data-statement">{{ 'No address given'|trans }}</span>
{% endif %}
</dd>
{% endif %}
{% if t.durationTimeVisible %}
<dt class="inline">{{ 'Duration Time'|trans }}</dt>
<dd>{% if entity.durationTime is not null %}

View File

@@ -4,7 +4,7 @@ namespace Chill\Migrations\Activity;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;
/**
* Add an "active" column on activitytype table

View File

@@ -22,7 +22,6 @@ final class Version20210401090853 extends AbstractMigration
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SEQUENCE activitytypecategory_id_seq INCREMENT BY 1 MINVALUE 1 START 1000');
$this->addSql('CREATE TABLE activitytypecategory (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))');
$this->addSql('COMMENT ON COLUMN activitytypecategory.name IS \'(DC2Type:json_array)\'');
$this->addSql('INSERT INTO activitytypecategory VALUES(1, \'{"fr": "Défaut", "en": "Default"}\', true)');
}

View File

@@ -51,7 +51,6 @@ final class Version20210408122329 extends AbstractMigration
$this->addSql('ALTER TABLE activitytype ADD socialDataLabel VARCHAR(255) DEFAULT \'\' NOT NULL');
$this->addSql('ALTER TABLE activitytype ALTER name SET NOT NULL');
$this->addSql('ALTER TABLE activitytype ALTER active DROP DEFAULT');
$this->addSql('COMMENT ON COLUMN activitytype.name IS \'(DC2Type:json_array)\'');
}
public function down(Schema $schema) : void

View File

@@ -6,7 +6,6 @@ Duration time: Durée
Duration Time: Durée
durationTime: durée
Travel time: Durée de déplacement
Reasons: Sujets
Attendee: Présence de la personne
attendee: présence de la personne
list_reasons: liste des sujets
@@ -23,6 +22,7 @@ Update: Mettre à jour
Update activity: Modifier l'activité
Scope: Cercle
Activity data: Données de l'activité
Activity location: Localisation de l'activité
No reason associated: Aucun sujet
No social issues associated: Aucune problématique sociale
No social actions associated: Aucune action d'accompagnement
@@ -99,10 +99,13 @@ CHILL_ACTIVITY_LIST: Liste des activités
Activities: Activités
Activity configuration: Configuration des activités
Activity configuration menu: Configuration des activités
Activity Types: Types d'activité
Activity types: Types d'activité
Activity type configuration: Configuration des categories d'activités
Activity Reasons: Sujets d'une activité
Activity Reasons Category: Catégories de sujet d'activités
Activity Types Categories: Catégories des types d'activité
Activity Presences: Presences des activités
# Crud
crud:

View File

@@ -19,8 +19,6 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
{
/**
* {@inheritdoc}
*
* @phpstan-ignore-next-line
*/
public function load(array $configs, ContainerBuilder $container): void
{
@@ -111,4 +109,4 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
]
]);
}
}
}

View File

@@ -58,7 +58,7 @@ final class AsideActivityFormType extends AbstractType
$builder
->add('agent', EntityType::class,
[
'label' => 'Agent',
'label' => 'For agent',
'required' => true,
'class' => User::class,
'data' => $this->storage->getToken()->getUser(),

View File

@@ -32,7 +32,7 @@ final class AdminMenuBuilder implements \Chill\MainBundle\Routing\LocalMenuBuild
])
->setExtras([
'order' => 900,
'explain' => "Configure aside activities categories"
'explain' => "Aside activity type configuration"
]);
} else {
$menu

View File

@@ -1,7 +1,7 @@
{% extends "@ChillAsideActivity/Admin/layout_asideactivity.html.twig" %}
{% block admin_content %}
<h1>{{ 'Aside Activity Type list'|trans }}</h1>
<h1>{{ 'Aside Activity Type List'|trans }}</h1>
<table class="records_list table table-bordered border-dark">
<thead>

View File

@@ -30,7 +30,9 @@ final class CategoryRender implements ChillEntityRenderInterface
{
$options = array_merge(self::DEFAULT_ARGS, $options);
$titles[] = $this->translatableStringHelper->localize($asideActivityCategory->getTitle());
$titles = [
$this->translatableStringHelper->localize($asideActivityCategory->getTitle()),
];
while ($asideActivityCategory->hasParent()) {
$asideActivityCategory = $asideActivityCategory->getParent();

View File

@@ -3,6 +3,7 @@ Show the aside activity: Voir l'activité annexe
Edit the aside activity: Modifier l'activité annexe
Remove aside activity: Supprimer l'activité annexe
Aside activity: Activité annexe
Aside Activity Type List: Liste des catégories d'activités annexes
Duration time: Durée
durationTime: durée
user_username: nom de l'utilisateur
@@ -45,7 +46,7 @@ Back to the list: Retour à la liste
Choose the duration: Choisir la durée
Choose a category: Choisir une catégorie
Is active: Actif
Agent: Utilisateur
For agent: Pour l'utilisateur
date: Date
Duration: Durée
Note: Note
@@ -156,6 +157,11 @@ The activity has been successfully removed.: L'activité a été supprimée.
#Menu
Create an aside activity: "Créer une activité annexe"
Aside activity categories: Catégories des activités annexes
Aside activity configuration menu: "Menu de configuration des activités annexes"
Aside activity configuration: "Configuration des activités annexes"
Phonecall: "Appel téléphonique"
# admin
Aside activities: Activités annexes
Aside activity types: Types d'activités annexes
Aside activity type configuration: Configuration des categories d'activités annexes

View File

@@ -97,9 +97,9 @@ class CalendarController extends AbstractController
'calendarItems' => $calendarItems,
'user' => $user
]);
}
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$total = $this->calendarRepository->countByAccompanyingPeriod($accompanyingPeriod);
$paginator = $this->paginator->create($total);
$calendarItems = $this->calendarRepository->findBy(
@@ -117,6 +117,8 @@ class CalendarController extends AbstractController
'paginator' => $paginator
]);
}
throw new \Exception('Unable to list actions.');
}
/**
@@ -234,6 +236,7 @@ class CalendarController extends AbstractController
'professionalsId' => $professionalsId,
'date' => $entity->getStartDate()->format('Y-m-d'),
'durationTime' => $durationTimeInMinutes,
'location' => $entity->getLocation()->getId(),
'comment' => $entity->getComment()->getComment(),
];

View File

@@ -2,6 +2,7 @@
namespace Chill\CalendarBundle\Entity;
use Chill\MainBundle\Entity\Location;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
@@ -136,6 +137,13 @@ class Calendar
*/
private ?bool $sendSMS;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Location")
* @groups({"read"})
*/
private ?Location $location = null;
public function __construct()
{
$this->comment = new CommentEmbeddable();
@@ -354,7 +362,7 @@ class Calendar
return $this;
}
public function getPersonsAssociated(): array
public function getPersonsAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
$personsAssociated = [];
@@ -363,11 +371,11 @@ class Calendar
$personsAssociated[] = $participation->getPerson();
}
}
return $personsAssociated;
return $personsAssociated;
}
return [];
}
public function getPersonsNotAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
@@ -407,4 +415,22 @@ class Calendar
]));
}
/**
* @return Location|null
*/
public function getLocation(): ?Location
{
return $this->location;
}
/**
* @param Location|null $location
* @return Calendar
*/
public function setLocation(?Location $location): Calendar
{
$this->location = $location;
return $this;
}
}

View File

@@ -34,7 +34,7 @@ class CancelReason
private $canceledBy;
/**
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name = [];

View File

@@ -25,7 +25,7 @@ class Invite
private User $user;
/**
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private array $status = [];

View File

@@ -2,6 +2,7 @@
namespace Chill\CalendarBundle\Form;
use Chill\MainBundle\Entity\Location;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -155,7 +156,7 @@ class CalendarType extends AbstractType
}
))
;
$builder->add('calendarRange', HiddenType::class);
$builder->get('calendarRange')
->addModelTransformer(new CallbackTransformer(
@@ -178,6 +179,20 @@ class CalendarType extends AbstractType
))
;
$builder->add('location', HiddenType::class)
->get('location')
->addModelTransformer(new CallbackTransformer(
function (?Location $location): string {
if (null === $location) {
return '';
}
return $location->getId();
},
function (?string $id): ?Location {
return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]);
}
))
;
// $builder->add('invites', HiddenType::class);
// $builder->get('invites')

View File

@@ -0,0 +1,92 @@
<?php
/*
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\CalendarBundle\Menu;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Chill\TaskBundle\Templating\UI\CountNotificationTask;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
*
* @author Champs-Libres
*/
class UserMenuBuilder implements LocalMenuBuilderInterface
{
/**
*
* @var CountNotificationTask
*/
public $counter;
/*
* @var TokenStorageInterface
*/
public $tokenStorage;
/**
*
* @var TranslatorInterface
*/
public $translator;
/**
*
* @var AuthorizationCheckerInterface
*/
public $authorizationChecker;
public function __construct(
CountNotificationTask $counter,
TokenStorageInterface $tokenStorage,
TranslatorInterface $translator,
AuthorizationCheckerInterface $authorizationChecker
) {
$this->counter = $counter;
$this->tokenStorage = $tokenStorage;
$this->translator = $translator;
$this->authorizationChecker = $authorizationChecker;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
$user = $this->tokenStorage->getToken()->getUser();
if ($this->authorizationChecker->isGranted('ROLE_USER')){
$menu->addChild("My calendar list", [
'route' => 'chill_calendar_calendar_list'
])
->setExtras([
'order' => 9,
'icon' => 'tasks'
]);
}
}
public static function getMenuIds(): array
{
return [ 'user' ];
}
}

View File

@@ -1,9 +1,10 @@
<template>
<concerned-groups></concerned-groups>
<location></location>
<teleport to="#calendarControls">
<calendar-user-selector
<calendar-user-selector
v-bind:users="users"
v-bind:calendarEvents="calendarEvents"
v-bind:calendarEvents="calendarEvents"
v-bind:updateEventsSource="updateEventsSource"
v-bind:showMyCalendar="showMyCalendar"
v-bind:toggleMyCalendar="toggleMyCalendar"
@@ -22,6 +23,7 @@
<script>
import ConcernedGroups from 'ChillActivityAssets/vuejs/Activity/components/ConcernedGroups.vue';
import Location from 'ChillActivityAssets/vuejs/Activity/components/Location.vue';
import CalendarUserSelector from '../_components/CalendarUserSelector/CalendarUserSelector.vue';
import '@fullcalendar/core/vdom'; // solves problem with Vite
import frLocale from '@fullcalendar/core/locales/fr';
@@ -35,6 +37,7 @@ export default {
name: "App",
components: {
ConcernedGroups,
Location,
CalendarUserSelector,
FullCalendar
},

View File

@@ -1,5 +1,6 @@
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
import { calendarUserSelectorMessages } from '../_components/CalendarUserSelector/js/i18n';
import { activityMessages } from 'ChillActivityAssets/vuejs/Activity/i18n';
const appMessages = {
fr: {
@@ -17,6 +18,7 @@ const appMessages = {
Object.assign(appMessages.fr, personMessages.fr);
Object.assign(appMessages.fr, calendarUserSelectorMessages.fr);
Object.assign(appMessages.fr, activityMessages.fr);
export {
appMessages

View File

@@ -66,6 +66,11 @@ const store = createStore({
setEvents(state, payload) {
console.log(payload)
state.currentEvent = {start: payload.start, end: payload.end}
},
// Location
updateLocation(state, value) {
console.log('### mutation: updateLocation', value);
state.activity.location = value;
}
},
actions: {
@@ -130,6 +135,14 @@ const store = createStore({
commit('setEvents', payload);
},
// Location
updateLocation({ commit }, value) {
console.log('### action: updateLocation', value);
let hiddenLocation = document.getElementById("chill_calendarbundle_calendar_location");
hiddenLocation.value = value.id;
commit('updateLocation', value);
}
}
});

View File

@@ -38,7 +38,10 @@
{{ form_row(form.calendarRange) }}
{% endif %}
.. location
{%- if form.location is defined -%}
{{ form_row(form.location) }}
<div id="location"></div>
{% endif %}
{%- if form.comment is defined -%}
{{ form_row(form.comment) }}
@@ -56,7 +59,7 @@
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a
<a
class="btn btn-cancel"
{%- if context == 'user' -%}
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'user_id': user.id } )}}"

View File

@@ -6,14 +6,10 @@
{% block content %}
<div class="calendar-edit">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
{% endblock %}
@@ -21,7 +17,7 @@
{{ parent() }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ form.vars.form.vars.name }}"]',
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.entity = {{ entity_json|json_encode|raw }};
@@ -40,4 +36,4 @@
{% block block_post_menu %}
<div id="calendarControls"></div>
{% endblock %}
{% endblock %}

View File

@@ -4,14 +4,10 @@
{% block content %}
<div class="calendar-edit">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'user'} %}
</div>
</div>
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'user'} %}
</div>
{% endblock %}
@@ -19,7 +15,7 @@
{{ parent() }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ form.vars.form.vars.name }}"]',
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.entity = {{ entity_json|json_encode|raw }};

View File

@@ -34,7 +34,10 @@
{{ form_row(form.endDate) }}
{% endif %}
.. location
{%- if form.location is defined -%}
{{ form_row(form.location) }}
<div id="location"></div>
{% endif %}
{%- if form.comment is defined -%}
{{ form_row(form.comment) }}
@@ -48,9 +51,9 @@
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a
<a
class="btn btn-cancel"
{%- if context == 'person' -%}
{%- if context == 'person' -%}
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'person_id': person.id } )}}"
{%- else -%}
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'accompanying_period_id': accompanyingCourse.id } )}}"

View File

@@ -6,25 +6,21 @@
{% block content %}
<div class="calendar-new">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:new.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
</div>
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:new.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
{% endblock %}
{% block js %}
{{ parent() }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.entity = {{ entity_json|json_encode|raw }};
window.entity = {{ entity_json|json_encode|raw }};
</script>
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}

View File

@@ -36,6 +36,20 @@
<dt class="inline">{{ 'status'|trans }}</dt>
<dd>{{ entity.status }}</dd>
<dt class="inline">{{ 'calendar location'|trans }}</dt>
<dd>
{% if entity.location is not null %}
<p>
<span>{{ entity.location.locationType.title|localize_translatable_string }}</span>
{{ entity.location.name }}
</p>
{{ entity.location.address|chill_entity_render_box }}
{% else %}
<span class="chill-no-data-statement">{{ 'No address given'|trans }}</span>
{% endif %}
</dd>
{% if not entity.comment.isEmpty %}
<dt class="inline">{{ 'calendar comment'|trans }}</dt>
<dd>{{ entity.comment|chill_entity_render_box }}</dd>

View File

@@ -6,10 +6,8 @@
{% block content -%}
<div class="calendar-show">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
</div>
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
{% endblock content %}

View File

@@ -4,10 +4,8 @@
{% block content -%}
<div class="calendar-show">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'user'} %}
</div>
</div>
</div>
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'user'} %}
</div>
{% endblock content %}

View File

@@ -50,10 +50,7 @@ final class Version20210715141731 extends AbstractMigration
$this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.startDate IS \'(DC2Type:date_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.endDate IS \'(DC2Type:date_immutable)\'');
$this->addSql('CREATE TABLE chill_calendar.cancel_reason (id INT NOT NULL, active BOOLEAN NOT NULL, canceledBy JSON NOT NULL, name JSON NOT NULL, PRIMARY KEY(id))');
$this->addSql('COMMENT ON COLUMN chill_calendar.cancel_reason.name IS \'(DC2Type:json_array)\'');
$this->addSql('COMMENT ON COLUMN chill_calendar.cancel_reason.canceledBy IS \'(DC2Type:json_array)\'');
$this->addSql('CREATE TABLE chill_calendar.invite (id INT NOT NULL, user_id INT DEFAULT NULL, status JSON NOT NULL, PRIMARY KEY(id))');
$this->addSql('COMMENT ON COLUMN chill_calendar.invite.status IS \'(DC2Type:json_array)\'');
$this->addSql('CREATE INDEX IDX_F517FFA7A76ED395 ON chill_calendar.invite (user_id)');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD CONSTRAINT FK_712315ACA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_calendar.calendar ADD CONSTRAINT FK_712315ACD7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
@@ -74,7 +71,7 @@ final class Version20210715141731 extends AbstractMigration
}
public function down(Schema $schema): void
{
{
$this->addSql('ALTER TABLE chill_calendar.calendar_to_persons DROP CONSTRAINT FK_AEE94715A40A2C8');
$this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals DROP CONSTRAINT FK_FADF2C77A40A2C8');
$this->addSql('ALTER TABLE chill_calendar.calendar_to_thirdparties DROP CONSTRAINT FK_2BAB7EFDA40A2C8');

View File

@@ -34,6 +34,5 @@ final class Version20210723074557 extends AbstractMigration
$this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals ADD CONSTRAINT fk_fadf2c77217bbb47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy TYPE JSON');
$this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy DROP DEFAULT');
$this->addSql('COMMENT ON COLUMN chill_calendar.cancel_reason.canceledby IS \'(DC2Type:json_array)\'');
}
}

View File

@@ -14,6 +14,7 @@ start date: début du rendez-vous
end date: fin du rendez-vous
cancel reason: motif d'annulation
status: Statut du rendez-vous
calendar location: Localistion du rendez-vous
calendar comment: Remarque sur le rendez-vous
sendSMS: Envoi d'un SMS
Send s m s: Envoi d'un SMS ?

View File

@@ -28,27 +28,31 @@ class ChillCustomFieldsExtension extends Extension implements PrependExtensionIn
$loader->load('services/fixtures.yaml');
$loader->load('services/controller.yaml');
$loader->load('services/command.yaml');
//add at least a blank array at 'customizable_entities' options
//$customizable_entities = (isset($config['customizables_entities'])
// && $config['customizables_entities'] !== FALSE)
//$customizable_entities = (isset($config['customizables_entities'])
// && $config['customizables_entities'] !== FALSE)
// ? $config['customizables_entities'] : array();
$container->setParameter('chill_custom_fields.customizables_entities',
$container->setParameter('chill_custom_fields.customizables_entities',
$config['customizables_entities']);
$container->setParameter('chill_custom_fields.show_empty_values',
$container->setParameter('chill_custom_fields.show_empty_values',
$config['show_empty_values_in_views']);
}
/* (non-PHPdoc)
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
*/
public function prepend(ContainerBuilder $container)
public function prepend(ContainerBuilder $container)
{
// add form layout to twig resources
$twigConfig['form_themes'][] = 'ChillCustomFieldsBundle:Form:fields.html.twig';
$twigConfig = [
'form_themes' => [
'ChillCustomFieldsBundle:Form:fields.html.twig',
],
];
$container->prependExtensionConfig('twig', $twigConfig);
//add routes for custom bundle
$container->prependExtensionConfig('chill_main', array(
'routing' => array(

View File

@@ -40,7 +40,7 @@ class CustomField
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
@@ -61,18 +61,18 @@ class CustomField
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* @var array
*
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $options = array();
/**
* @var array
*
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
@@ -82,14 +82,14 @@ class CustomField
* @ORM\Column(type="float")
*/
private $ordering;
/**
* @var boolean
*
* @ORM\Column(type="boolean")
*/
private $required = FALSE;
const ONE_TO_ONE = 1;
const ONE_TO_MANY = 2;
@@ -102,7 +102,7 @@ class CustomField
*/
private $customFieldGroup;
/**
* Get id
*
@@ -112,7 +112,7 @@ class CustomField
{
return $this->id;
}
/**
* @return string
*/
@@ -120,15 +120,15 @@ class CustomField
{
return $this->slug;
}
/**
* @return array
*/
function getOptions()
{
return $this->options;
}
}
/**
* Set type
*
@@ -152,7 +152,7 @@ class CustomField
return $this->type;
}
/**
* Set active
*
@@ -229,9 +229,9 @@ class CustomField
}
}
}
return '';
} else {
return $this->name;
};
@@ -272,7 +272,7 @@ class CustomField
return $this;
}
/**
* @param $slug
* @return $this
@@ -282,20 +282,20 @@ class CustomField
$this->slug = $slug;
return $this;
}
/**
* alias for isRequired
*
*
* @return boolean
*/
public function getRequired()
{
return $this->isRequired();
}
/**
* return true if the field required
*
*
* @return boolean
*/
public function isRequired()
@@ -308,5 +308,5 @@ class CustomField
$this->required = $required;
return $this;
}
}

View File

@@ -39,21 +39,21 @@ class Option
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
* @ORM\Column(type="string", length=15)
*/
private $key;
/**
* A json representation of text (multilingual)
*
* @var array
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $text;
/**
* @var Collection
* @ORM\OneToMany(
@@ -61,7 +61,7 @@ class Option
* mappedBy="parent")
*/
private $children;
/**
* @var Option
* @ORM\ManyToOne(
@@ -70,19 +70,19 @@ class Option
* @ORM\JoinColumn(nullable=true)
*/
private $parent;
/**
* @var string
* @ORM\Column(type="string", length=50, name="internal_key")
*/
private $internalKey = '';
/**
* @var boolean
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* @return int
*/
@@ -90,7 +90,7 @@ class Option
{
return $this->id;
}
/**
* @return string
*/
@@ -98,7 +98,7 @@ class Option
{
return $this->key;
}
/**
* @return array
*/
@@ -106,7 +106,7 @@ class Option
{
return $this->text;
}
/**
* @return Collection
*/
@@ -114,7 +114,7 @@ class Option
{
return $this->children;
}
/**
* @return Option
*/
@@ -122,7 +122,7 @@ class Option
{
return $this->parent;
}
/**
* @param $key
* @return $this
@@ -132,7 +132,7 @@ class Option
$this->key = $key;
return $this;
}
/**
* @param array $text
* @return $this
@@ -142,7 +142,7 @@ class Option
$this->text = $text;
return $this;
}
/**
* @param Option|null $parent
* @return $this
@@ -153,16 +153,16 @@ class Option
$this->key = $parent->getKey();
return $this;
}
/**
*
*
* @return boolean
*/
public function hasParent()
{
return $this->parent === NULL ? false : true;
}
/**
* @return string
*/
@@ -170,7 +170,7 @@ class Option
{
return $this->internalKey;
}
/**
* @return bool
*/
@@ -178,7 +178,7 @@ class Option
{
return $this->active;
}
/**
* @return bool
*/
@@ -186,7 +186,7 @@ class Option
{
return $this->isActive();
}
/**
* @param $internal_key
* @return $this
@@ -196,7 +196,7 @@ class Option
$this->internalKey = $internal_key;
return $this;
}
/**
* @param $active
* @return $this
@@ -206,5 +206,5 @@ class Option
$this->active = $active;
return $this;
}
}

View File

@@ -45,7 +45,7 @@ class CustomFieldsGroup
/**
* @var array
*
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
@@ -76,15 +76,15 @@ class CustomFieldsGroup
* @var array|null
*/
private $activeCustomFields = null;
/**
* @var array
*
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $options = array();
/**
* CustomFieldsGroup constructor.
*/
@@ -115,7 +115,7 @@ class CustomFieldsGroup
{
$this->customFields->removeElement($customField);
}
/**
* @return Collection
*/
@@ -142,7 +142,7 @@ class CustomFieldsGroup
return $this->activeCustomFields;
}
/**
* Get id
*
@@ -184,9 +184,9 @@ class CustomFieldsGroup
}
}
}
return '';
} else {
return $this->name;
}
@@ -214,10 +214,10 @@ class CustomFieldsGroup
{
return $this->entity;
}
/**
* get options array
*
*
* @return array
*/
public function getOptions()
@@ -227,7 +227,7 @@ class CustomFieldsGroup
/**
* set options array
*
*
* @param array $options
* @return CustomFieldsGroup
*/

View File

@@ -145,5 +145,7 @@ class DocGeneratorTemplateController extends AbstractController
} catch (TransferException $e) {
throw $e;
}
throw new \Exception('Unable to generate document.');
}
}

View File

@@ -21,7 +21,7 @@ class DocGeneratorTemplate
private int $id;
/**
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
* @Serializer\Groups({"read"})
*/
private array $name = [];

View File

@@ -22,7 +22,6 @@ final class Version20210812214310 extends AbstractMigration
$this->addSql('ALTER TABLE chill_docgen_template ADD entities TEXT');
$this->addSql('ALTER TABLE chill_docgen_template ADD context VARCHAR(255)');
$this->addSql('COMMENT ON COLUMN chill_docgen_template.entities IS \'(DC2Type:simple_array)\'');
$this->addSql('COMMENT ON COLUMN chill_docgen_template.name IS \'(DC2Type:json_array)\'');
}
public function down(Schema $schema): void

View File

@@ -4,6 +4,7 @@ namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Privacy\PrivacyEvent;
@@ -16,32 +17,27 @@ use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class DocumentAccompanyingCourseController
*
* @package Chill\DocStoreBundle\Controller
* @Route("/{_locale}/parcours/{course}/document")
*
* TODO faire un controller abstrait ?
*/
class DocumentAccompanyingCourseController extends AbstractController
{
/**
*
* @var TranslatorInterface
*/
protected $translator;
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
* DocumentAccompanyingCourseController constructor.
@@ -50,15 +46,15 @@ class DocumentAccompanyingCourseController extends AbstractController
* @param AuthorizationHelper $authorizationHelper
*/
public function __construct(
TranslatorInterface $translator,
EventDispatcherInterface $eventDispatcher,
TranslatorInterface $translator,
EventDispatcherInterface $eventDispatcher,
AuthorizationHelper $authorizationHelper
) {
$this->translator = $translator;
$this->eventDispatcher = $eventDispatcher;
$this->authorizationHelper = $authorizationHelper;
}
/**
* @Route("/", name="accompanying_course_document_index", methods="GET")
*/
@@ -70,7 +66,7 @@ class DocumentAccompanyingCourseController extends AbstractController
throw $this->createNotFoundException('Accompanying period not found');
}
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $course);
$this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::SEE, $course);
$documents = $em
->getRepository("ChillDocStoreBundle:AccompanyingCourseDocument")
@@ -78,7 +74,7 @@ class DocumentAccompanyingCourseController extends AbstractController
['course' => $course],
['date' => 'DESC']
);
return $this->render(
'ChillDocStoreBundle:AccompanyingCourseDocument:index.html.twig',
[
@@ -96,13 +92,13 @@ class DocumentAccompanyingCourseController extends AbstractController
throw $this->createNotFoundException('Accompanying period not found');
}
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $course);
$document = new AccompanyingCourseDocument();
$document->setUser($this->getUser());
$document->setCourse($course);
$document->setDate(new \DateTime('Now'));
$this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::CREATE, $document);
$form = $this->createForm(AccompanyingCourseDocumentType::class, $document);
$form->handleRequest($request);
@@ -114,7 +110,7 @@ class DocumentAccompanyingCourseController extends AbstractController
$em = $this->getDoctrine()->getManager();
$em->persist($document);
$em->flush();
$this->addFlash('success', $this->translator->trans("The document is successfully registered"));
return $this->redirectToRoute('accompanying_course_document_index', ['course' => $course->getId()]);
@@ -134,9 +130,8 @@ class DocumentAccompanyingCourseController extends AbstractController
*/
public function show(AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
{
$this->denyAccessUnlessGranted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', $course);
$this->denyAccessUnlessGranted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE', $document);
$this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::SEE_DETAILS, $document);
return $this->render(
'ChillDocStoreBundle:AccompanyingCourseDocument:show.html.twig',
['document' => $document, 'accompanyingCourse' => $course]);
@@ -147,8 +142,7 @@ class DocumentAccompanyingCourseController extends AbstractController
*/
public function edit(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
{
$this->denyAccessUnlessGranted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', $course);
$this->denyAccessUnlessGranted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', $document);
$this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::UPDATE, $document);
$document->setUser($this->getUser());
$document->setDate(new \DateTime('Now'));
@@ -159,17 +153,17 @@ class DocumentAccompanyingCourseController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator->trans("The document is successfully updated"));
return $this->redirectToRoute(
'accompanying_course_document_edit',
['id' => $document->getId(), 'course' => $course->getId()]);
} elseif ($form->isSubmitted() and !$form->isValid()) {
$this->addFlash('error', $this->translator->trans("This form contains errors"));
}
return $this->render(
'ChillDocStoreBundle:AccompanyingCourseDocument:edit.html.twig',
[
@@ -184,8 +178,7 @@ class DocumentAccompanyingCourseController extends AbstractController
*/
public function delete(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
{
$this->denyAccessUnlessGranted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', $course);
$this->denyAccessUnlessGranted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', $document);
$this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::DELETE, $document);
if ($this->isCsrfTokenValid('delete'.$document->getId(), $request->request->get('_token'))) {
$em = $this->getDoctrine()->getManager();

View File

@@ -2,6 +2,7 @@
namespace Chill\DocStoreBundle\DependencyInjection;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
@@ -39,7 +40,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf
$this->prependAuthorization($container);
$this->prependTwig($container);
}
protected function prependRoute(ContainerBuilder $container)
{
//declare routes for task bundle
@@ -52,7 +53,7 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf
)
));
}
protected function prependAuthorization(ContainerBuilder $container)
{
$container->prependExtensionConfig('security', array(
@@ -61,10 +62,14 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf
PersonDocumentVoter::CREATE => [PersonDocumentVoter::SEE_DETAILS],
PersonDocumentVoter::DELETE => [PersonDocumentVoter::SEE_DETAILS],
PersonDocumentVoter::SEE_DETAILS => [PersonDocumentVoter::SEE],
AccompanyingCourseDocumentVoter::UPDATE => [AccompanyingCourseDocumentVoter::SEE_DETAILS],
AccompanyingCourseDocumentVoter::CREATE => [AccompanyingCourseDocumentVoter::SEE_DETAILS],
AccompanyingCourseDocumentVoter::DELETE => [AccompanyingCourseDocumentVoter::SEE_DETAILS],
AccompanyingCourseDocumentVoter::SEE_DETAILS => [AccompanyingCourseDocumentVoter::SEE],
)
));
}
protected function prependTwig(ContainerBuilder $container)
{
$twigConfig = array(

View File

@@ -34,10 +34,10 @@ class DocumentCategory
/**
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
public function __construct($bundleId, $idInsideBundle)
{
$this->bundleId = $bundleId;

View File

@@ -39,14 +39,14 @@ class StoredObject implements AsyncFileInterface, Document
private $filename;
/**
* @ORM\Column(type="json_array", name="key")
* @ORM\Column(type="json", name="key")
*/
private array $keyInfos = [];
/**
*
* @var int[]
* @ORM\Column(type="json_array", name="iv")
* @ORM\Column(type="json", name="iv")
*/
private array $iv = [];
@@ -69,7 +69,7 @@ class StoredObject implements AsyncFileInterface, Document
private string $type = '';
/**
* @ORM\Column(type="json_array", name="datas")
* @ORM\Column(type="json", name="datas")
* @Serializer\Groups({"read"})
*/
private array $datas = [];

View File

@@ -1,8 +1,10 @@
<?php
namespace Chill\DocStoreBundle\Repository;
declare(strict_types=1);
use App\Entity\AccompanyingCourseDocument;
namespace Chill\DocStoreBundle\EntityRepository;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

View File

@@ -3,50 +3,27 @@
*/
namespace Chill\DocStoreBundle\Menu;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Knp\Menu\MenuItem;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class MenuBuilder implements LocalMenuBuilderInterface
final class MenuBuilder implements LocalMenuBuilderInterface
{
/**
*
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
*
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
*
* @var TranslatorInterface
*/
protected $translator;
private Security $security;
protected TranslatorInterface $translator;
public function __construct(
TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper,
Security $security,
TranslatorInterface $translator
){
$this->tokenStorage = $tokenStorage;
$this->authorizationHelper = $authorizationHelper;
) {
$this->security = $security;
$this->translator = $translator;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
switch($menuId) {
@@ -65,11 +42,8 @@ class MenuBuilder implements LocalMenuBuilderInterface
{
/* @var $person \Chill\PersonBundle\Entity\Person */
$person = $parameters['person'];
$user = $this->tokenStorage->getToken()->getUser();
if ($this->authorizationHelper->userHasAccess($user,
$person->getCenter(), PersonDocumentVoter::SEE)) {
if ($this->security->isGranted(PersonDocumentVoter::SEE, $person)) {
$menu->addChild($this->translator->trans('Documents'), [
'route' => 'person_document_index',
'routeParameters' => [
@@ -80,24 +54,22 @@ class MenuBuilder implements LocalMenuBuilderInterface
'order'=> 350
]);
}
}
protected function buildMenuAccompanyingCourse(MenuItem $menu, array $parameters){
$course = $parameters['accompanyingCourse'];
// $user = $this->tokenStorage->getToken()->getUser();
//TODO : add condition to check user rights?
$menu->addChild($this->translator->trans('Documents'), [
if ($this->security->isGranted(AccompanyingCourseDocumentVoter::SEE, $course)) {
$menu->addChild($this->translator->trans('Documents'), [
'route' => 'accompanying_course_document_index',
'routeParameters' => [
'course' => $course->getId()
]
])
->setExtras([
'order'=> 400
]);
->setExtras([
'order' => 400
]);
}
}
public static function getMenuIds(): array

View File

@@ -3,13 +3,20 @@
namespace Chill\DocStoreBundle\Security\Authorization;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Security;
/**
*
@@ -22,30 +29,22 @@ class AccompanyingCourseDocumentVoter extends AbstractChillVoter implements Prov
const UPDATE = 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE';
const DELETE = 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE';
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
* @var AccessDecisionManagerInterface
*/
protected $accessDecisionManager;
/**
* @var LoggerInterface
*/
protected $logger;
protected LoggerInterface $logger;
protected VoterHelperInterface $voterHelper;
protected Security $security;
public function __construct(
AccessDecisionManagerInterface $accessDecisionManager,
AuthorizationHelper $authorizationHelper,
LoggerInterface $logger
)
{
$this->accessDecisionManager = $accessDecisionManager;
$this->authorizationHelper = $authorizationHelper;
LoggerInterface $logger,
Security $security,
VoterHelperFactoryInterface $voterHelperFactory
) {
$this->logger = $logger;
$this->security = $security;
$this->voterHelper = $voterHelperFactory
->generate(self::class)
->addCheckFor(AccompanyingCourseDocument::class, $this->getRoles())
->addCheckFor(AccompanyingPeriod::class, [self::SEE, self::CREATE])
->build();
}
public function getRoles()
@@ -61,26 +60,30 @@ class AccompanyingCourseDocumentVoter extends AbstractChillVoter implements Prov
protected function supports($attribute, $subject)
{
if (\in_array($attribute, $this->getRoles())) {
return true;
}
return false;
return $this->voterHelper->supports($attribute, $subject);
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
return true;
}
$this->logger->debug(sprintf("Voting from %s class", self::class));
if (!$token->getUser() instanceof User) {
return false;
}
if ($subject instanceof AccompanyingCourseDocument
&& !$this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getCourse())) {
return false;
}
return $this->voterHelper->voteOnAttribute($attribute, $subject, $token);
}
public function getRolesWithoutScope()
{
return array();
}
public function getRolesWithHierarchy()
{
return ['accompanyingCourseDocument' => $this->getRoles() ];

View File

@@ -19,8 +19,11 @@
namespace Chill\DocStoreBundle\Security\Authorization;
use App\Security\Authorization\VoterHelperFactory;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
@@ -31,6 +34,7 @@ use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Role\Role;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Security;
/**
*
@@ -43,25 +47,22 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera
const UPDATE = 'CHILL_PERSON_DOCUMENT_UPDATE';
const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE';
protected AuthorizationHelper $authorizationHelper;
protected AccessDecisionManagerInterface $accessDecisionManager;
protected LoggerInterface $logger;
protected CenterResolverDispatcher $centerResolverDispatcher;
protected Security $security;
protected VoterHelperInterface $voterHelper;
public function __construct(
AccessDecisionManagerInterface $accessDecisionManager,
AuthorizationHelper $authorizationHelper,
LoggerInterface $logger//,
//CenterResolverDispatcher $centerResolverDispatcher
)
{
$this->accessDecisionManager = $accessDecisionManager;
$this->authorizationHelper = $authorizationHelper;
LoggerInterface $logger,
Security $security,
VoterHelperFactoryInterface $voterHelperFactory
) {
$this->logger = $logger;
//$this->centerResolverDispatcher = $centerResolverDispatcher;
$this->security = $security;
$this->voterHelper = $voterHelperFactory
->generate(self::class)
->addCheckFor(PersonDocument::class, $this->getRoles())
->addCheckFor(Person::class, [self::SEE, self::CREATE])
->build();
}
public function getRoles()
@@ -77,16 +78,7 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera
protected function supports($attribute, $subject)
{
if (\in_array($attribute, $this->getRoles()) && $subject instanceof PersonDocument) {
return true;
}
if ($subject instanceof Person
&& \in_array($attribute, [self::CREATE, self::SEE])) {
return true;
}
return false;
return $this->voterHelper->supports($attribute, $subject);
}
/**
@@ -104,42 +96,12 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera
return false;
}
$center = $this->centerResolverDispatcher->resolveCenter($subject);
if ($subject instanceof PersonDocument) {
return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute);
} elseif ($subject instanceof Person) {
return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute);
} else {
// subject is null. We check that at least one center is reachable
$centers = $this->authorizationHelper
->getReachableCenters($token->getUser(), new Role($attribute));
return count($centers) > 0;
}
if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {
if ($subject instanceof PersonDocument
&& !$this->security->isGranted(PersonVoter::SEE, $subject->getPerson())) {
return false;
}
return $this->authorizationHelper->userHasAccess(
$token->getUser(),
$subject,
$attribute
);
}
protected function isGranted($attribute, $report, $user = null)
{
if (! $user instanceof User){
return false;
}
return $this->helper->userHasAccess($user, $report, $attribute);
return $this->voterHelper->voteOnAttribute($attribute, $subject, $token);
}
public function getRolesWithoutScope()

View File

@@ -1,8 +1,4 @@
services:
Chill\DocStoreBundle\Menu\MenuBuilder:
arguments:
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
$translator: '@Symfony\Component\Translation\TranslatorInterface'
tags:
- { name: 'chill.menu_builder' }
autowire: true
autoconfigure: true

View File

@@ -17,7 +17,6 @@ final class Version20180605102533 extends AbstractMigration
$this->addSql('CREATE SCHEMA chill_doc');
$this->addSql('CREATE SEQUENCE chill_doc.person_document_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE chill_doc.document_category (bundle_id VARCHAR(255) NOT NULL, id_inside_bundle INT NOT NULL, document_class VARCHAR(255) NOT NULL, name JSON NOT NULL, PRIMARY KEY(bundle_id, id_inside_bundle))');
$this->addSql('COMMENT ON COLUMN chill_doc.document_category.name IS \'(DC2Type:json_array)\'');
$this->addSql('CREATE TABLE chill_doc.person_document (id INT NOT NULL, category_bundle_id VARCHAR(255) DEFAULT NULL, category_id_inside_bundle INT DEFAULT NULL, scope_id INT DEFAULT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, title TEXT NOT NULL, description TEXT NOT NULL, content TEXT NOT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_41DA53C369A0BE36EF62EFC ON chill_doc.person_document (category_bundle_id, category_id_inside_bundle)');
$this->addSql('CREATE INDEX IDX_41DA53C682B5931 ON chill_doc.person_document (scope_id)');
@@ -34,6 +33,6 @@ final class Version20180605102533 extends AbstractMigration
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('DROP SCHEMA chill_doc CASCADE');
}
}

View File

@@ -16,9 +16,6 @@ final class Version20180606133338 extends AbstractMigration
$this->addSql('CREATE SEQUENCE chill_doc.stored_object_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE chill_doc.stored_object (id INT NOT NULL, filename TEXT NOT NULL, key JSON NOT NULL, iv JSON NOT NULL, creation_date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, type TEXT NOT NULL, datas JSON NOT NULL, PRIMARY KEY(id))');
$this->addSql('COMMENT ON COLUMN chill_doc.stored_object.key IS \'(DC2Type:json_array)\'');
$this->addSql('COMMENT ON COLUMN chill_doc.stored_object.iv IS \'(DC2Type:json_array)\'');
$this->addSql('COMMENT ON COLUMN chill_doc.stored_object.datas IS \'(DC2Type:json_array)\'');
$this->addSql('ALTER TABLE chill_doc.person_document ADD object_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE chill_doc.person_document DROP content');
$this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C232D562B FOREIGN KEY (object_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE');

View File

@@ -39,12 +39,12 @@ use Symfony\Component\Form\Extension\Core\Type\CollectionType;
*/
class ParticipationController extends AbstractController
{
/**
* @var \Psr\Log\LoggerInterface
*/
private $logger;
/**
* ParticipationController constructor.
*
@@ -54,10 +54,10 @@ class ParticipationController extends AbstractController
{
$this->logger = $logger;
}
/**
* Show a form to add a participation
*
*
* This function parse the person_id / persons_ids query argument
* and decide if it should process a single or multiple participation. Depending
* on this, the appropriate layout and form.
@@ -67,46 +67,46 @@ class ParticipationController extends AbstractController
*/
public function newAction(Request $request)
{
// test the request is correct
try {
$this->testRequest($request);
} catch (\RuntimeException $ex) {
$this->logger->warning($ex->getMessage());
return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST)
->setContent($ex->getMessage());
}
// forward to other action
$single = $request->query->has('person_id');
$multiple = $request->query->has('persons_ids');
if ($single === true) {
return $this->newSingle($request);
}
if ($multiple === true) {
return $this->newMultiple($request);
}
// at this point, we miss the required fields. Throw an error
return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST)
->setContent("You must provide either 'person_id' or "
. "'persons_ids' argument in query");
}
/**
*
*
* Test that the query parameters are valid :
*
*
* - an `event_id` is existing ;
* - `person_id` and `persons_ids` are **not** both present ;
* - `persons_id` is correct (contains only numbers and a ','.
*
*
* @param Request $request
* @throws \RuntimeException if an error is detected
*/
@@ -114,64 +114,64 @@ class ParticipationController extends AbstractController
{
$single = $request->query->has('person_id');
$multiple = $request->query->has('persons_ids');
if ($single === true AND $multiple === true) {
// we are not allowed to have both person_id and persons_ids
throw new \RuntimeException("You are not allow to provide both 'person_id' and "
. "'persons_ids' simulaneously");
}
if ($multiple === true) {
$persons_ids = $request->query->get('persons_ids');
if (!preg_match('/^([0-9]{1,},{0,1}){1,}[0-9]{0,}$/', $persons_ids)) {
throw new \RuntimeException("The persons_ids value should "
. "contains int separated by ','");
}
}
// check for event_id - this could be removed later
if ($request->query->has('event_id') === FALSE) {
throw new \RuntimeException("You must provide an event_id");
}
}
/**
* Show a form with single participation.
*
*
* @param Request $request
* @return Response
*/
protected function newSingle(Request $request)
{
$returnPath = $request->query->get('return_path') ?
$request->query->get('return_path') : null;
$participation = $this->handleRequest($request, new Participation(), false);
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$participation, 'The user is not allowed to create this participation');
$form = $this->createCreateForm($participation, $returnPath);
return $this->render('ChillEventBundle:Participation:new.html.twig', array(
'form' => $form->createView(),
'participation' => $participation,
'ignored_participations' => array() // this is required, see self::newMultiple
));
}
/**
* Show a form with multiple participation.
*
*
* If a person is already participating on the event (if a participation with
* the same person is associated with the event), the participation is ignored.
*
*
* If all but one participation is ignored, the page show the same response
* than the newSingle function.
*
* than the newSingle function.
*
* If all participations must be ignored, an error is shown and the method redirects
* to the event 'show' view with an appropriate flash message.
*
@@ -181,24 +181,24 @@ class ParticipationController extends AbstractController
protected function newMultiple(Request $request)
{
$participations = $this->handleRequest($request, new Participation(), true);
$ignoredParticipations = $newParticipations = [];
foreach ($participations as $i => $participation) {
// check for authorization
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$participation, 'The user is not allowed to create this participation');
// create a collection of person's id participating to the event
/* @var $peopleParticipating \Doctrine\Common\Collections\ArrayCollection */
$peopleParticipating = isset($peopleParticipating) ? $peopleParticipating :
$participation->getEvent()->getParticipations()->map(
function(Participation $p) { return $p->getPerson()->getId(); }
);
// check that the user is not already in the event
// check that the user is not already in the event
if ($peopleParticipating->contains($participation->getPerson()->getId())) {
$ignoredParticipations[] = $participation
->getEvent()->getParticipations()->filter(
function (Participation $p) use ($participation) {
function (Participation $p) use ($participation) {
return $p->getPerson()->getId() === $participation->getPerson()->getId();
}
)->first();
@@ -206,15 +206,15 @@ class ParticipationController extends AbstractController
$newParticipations[] = $participation;
}
}
// this is where the function redirect depending on valid participation
if (!isset($newParticipations)) {
if ([] === $newParticipations) {
// if we do not have nay participants, redirect to event view
$this->addFlash('error', $this->get('translator')->trans(
'None of the requested people may participate '
. 'the event: they are maybe already participating.'));
return $this->redirectToRoute('chill_event__event_show', array(
'event_id' => $request->query->getInt('event_id', 0)
));
@@ -222,24 +222,29 @@ class ParticipationController extends AbstractController
// if we have multiple participations, show a form with multiple participations
$form = $this->createCreateFormMultiple($newParticipations);
return $this->render('ChillEventBundle:Participation:new-multiple.html.twig', array(
return $this->render(
'ChillEventBundle:Participation:new-multiple.html.twig',
[
'form' => $form->createView(),
'participations' => $newParticipations,
'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array()
));
} else {
// if we have only one participation, show the same form than for single participation
$form = $this->createCreateForm($participation);
return $this->render('ChillEventBundle:Participation:new.html.twig', array(
'ignored_participations' => $ignoredParticipations
]
);
}
// if we have only one participation, show the same form than for single participation
$form = $this->createCreateForm($participation);
return $this->render(
'ChillEventBundle:Participation:new.html.twig',
[
'form' => $form->createView(),
'participation' => $participation,
'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array()
));
}
'ignored_participations' => $ignoredParticipations,
]
);
}
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
@@ -251,32 +256,32 @@ class ParticipationController extends AbstractController
$this->testRequest($request);
} catch (\RuntimeException $ex) {
$this->logger->warning($ex->getMessage());
return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST)
->setContent($ex->getMessage());
}
// forward to other action
$single = $request->query->has('person_id');
$multiple = $request->query->has('persons_ids');
if ($single === true) {
return $this->createSingle($request);
}
if ($multiple === true) {
return $this->createMultiple($request);
}
// at this point, we miss the required fields. Throw an error
return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST)
->setContent("You must provide either 'person_id' or "
. "'persons_ids' argument in query");
}
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
@@ -284,41 +289,41 @@ class ParticipationController extends AbstractController
public function createSingle(Request $request)
{
$participation = $this->handleRequest($request, new Participation(), false);
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$participation, 'The user is not allowed to create this participation');
$form = $this->createCreateForm($participation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($participation);
$em->flush();
$this->addFlash('success', $this->get('translator')->trans(
'The participation was created'
));
if ($request->query->get('return_path'))
{
return $this->redirect($request->query->get('return_path'));
} else {
return $this->redirectToRoute('chill_event__event_show', array(
'event_id' => $participation->getEvent()->getId()
));
}
}
return $this->render('ChillEventBundle:Participation:new.html.twig', array(
'form' => $form->createView(),
'participation' => $participation
));
}
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
@@ -326,56 +331,56 @@ class ParticipationController extends AbstractController
public function createMultiple(Request $request)
{
$participations = $this->handleRequest($request, new Participation(), true);
foreach($participations as $participation) {
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$participation, 'The user is not allowed to create this participation');
}
$form = $this->createCreateFormMultiple($participations);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$data = $form->getData();
foreach($data['participations'] as $participation) {
$em->persist($participation);
}
$em->flush();
$this->addFlash('success', $this->get('translator')->trans(
'The participations were created'
));
return $this->redirectToRoute('chill_event__event_show', array(
'event_id' => $participations[0]->getEvent()->getId()
));
}
return $this->render('ChillEventBundle:Participation:new.html.twig', array(
'form' => $form->createView(),
'participation' => $participation
));
}
/**
*
*
* Handle the request to adapt $participation.
*
* If the request is multiple, the $participation object is cloned.
*
* If the request is multiple, the $participation object is cloned.
* Limitations: the $participation should not be persisted.
*
*
* @param Request $request
* @param Participation $participation
* @param boolean $multiple (default false)
* @param boolean $multiple (default false)
* @return Participation|Participations[] return one single participation if $multiple == false
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the event/person is not found
* @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException if the user does not have access to event/person
*/
protected function handleRequest(
Request $request,
Request $request,
Participation $participation,
$multiple = false)
{
@@ -384,37 +389,37 @@ class ParticipationController extends AbstractController
throw new \LogicException("The participation object should not be managed by "
. "the object manager using the method ".__METHOD__);
}
$event_id = $request->query->getInt('event_id', 0); // sf4 check:
// prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given`
if ($event_id !== NULL) {
$event = $em->getRepository('ChillEventBundle:Event')
->find($event_id);
if ($event === NULL) {
throw $this->createNotFoundException('The event with id '.$event_id.' is not found');
}
$this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event,
$this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event,
'The user is not allowed to see the event');
$participation->setEvent($event);
}
// this script should be able to handle multiple, so we translate
// this script should be able to handle multiple, so we translate
// single person_id in an array
$persons_ids = $request->query->has('person_id') ?
[$request->query->getInt('person_id', 0)] // sf4 check:
// prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given`
: explode(',', $request->query->get('persons_ids'));
$participations = array();
foreach($persons_ids as $person_id) {
// clone if we have to reuse the $participation
$participation = count($persons_ids) > 1 ? clone $participation : $participation;
if ($person_id !== NULL) {
$person = $em->getRepository('ChillPersonBundle:Person')
->find($person_id);
@@ -428,13 +433,13 @@ class ParticipationController extends AbstractController
$participation->setPerson($person);
}
$participations[] = $participation;
}
return $multiple ? $participations : $participations[0];
}
/**
* @param Participation $participation
* @param null $return_path
@@ -442,7 +447,7 @@ class ParticipationController extends AbstractController
*/
public function createCreateForm(Participation $participation, $return_path = null)
{
$form = $this->createForm(ParticipationType::class, $participation, array(
'event_type' => $participation->getEvent()->getType(),
'action' => $this->generateUrl('chill_event_participation_create', array(
@@ -451,14 +456,14 @@ class ParticipationController extends AbstractController
'person_id' => $participation->getPerson()->getId()
))
));
$form->add('submit', SubmitType::class, array(
'label' => 'Create'
));
return $form;
}
/**
* @param array $participations
* @return \Symfony\Component\Form\FormInterface
@@ -470,7 +475,7 @@ class ParticipationController extends AbstractController
'action' => $this->generateUrl('chill_event_participation_create', array(
'event_id' => current($participations)->getEvent()->getId(),
'persons_ids' => implode(',', array_map(
function(Participation $p) { return $p->getPerson()->getId(); },
function(Participation $p) { return $p->getPerson()->getId(); },
$participations))
)
)));
@@ -481,90 +486,90 @@ class ParticipationController extends AbstractController
),
)
);
$form->add('submit', SubmitType::class, array(
'label' => 'Create'
));
return $form;
}
/**
* show an edit form for the participation with the given id.
*
*
* @param int $participation_id
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the participation is not found
* @throws \Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException if the user is not allowed to edit the participation
*/
public function editAction($participation_id)
public function editAction($participation_id)
{
/* @var $participation Participation */
$participation = $this->getDoctrine()->getManager()
->getRepository('ChillEventBundle:Participation')
->find($participation_id);
if ($participation === NULL) {
throw $this->createNotFoundException('The participation is not found');
}
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
'You are not allowed to edit this participation');
$form = $this->createEditForm($participation);
return $this->render('ChillEventBundle:Participation:edit.html.twig', array(
'form' => $form->createView(),
'participation' => $participation
));
}
/**
* @param $participation_id
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
*/
public function updateAction($participation_id, Request $request)
public function updateAction($participation_id, Request $request)
{
/* @var $participation Participation */
$participation = $this->getDoctrine()->getManager()
->getRepository('ChillEventBundle:Participation')
->find($participation_id);
if ($participation === NULL) {
throw $this->createNotFoundException('The participation is not found');
}
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
'You are not allowed to edit this participation');
$form = $this->createEditForm($participation);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->flush();
$this->addFlash('success', $this->get('translator')->trans(
'The participation was updated'
));
return $this->redirectToRoute('chill_event__event_show', array(
'event_id' => $participation->getEvent()->getId()
));
}
return $this->render('ChillEventBundle:Participation:edit.html.twig', array(
'form' => $form->createView(),
'participation' => $participation
));
}
/**
*
*
* @param Participation $participation
* @return \Symfony\Component\Form\FormInterface
*/
@@ -576,14 +581,14 @@ class ParticipationController extends AbstractController
'participation_id' => $participation->getId()
))
));
$form->add('submit', SubmitType::class, array(
'label' => 'Edit'
));
return $form;
}
/**
* show a form to edit multiple participation for the same event.
*
@@ -594,84 +599,84 @@ class ParticipationController extends AbstractController
{
$event = $this->getDoctrine()->getRepository('ChillEventBundle:Event')
->find($event_id);
if ($event === null) {
throw $this->createNotFoundException("The event with id $event_id is not found");
}
// check for ACL, on Event level and on Participation Level
$this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event, "You are not allowed "
. "to see this event");
foreach ($event->getParticipations() as $participation) {
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
"You are not allowed to update participation with id ".$participation->getId());
}
switch ($event->getParticipations()->count()) {
case 0:
// if there aren't any participation, redirect to the 'show' view with an add flash
$this->addFlash('warning', $this->get('translator')
->trans( "There are no participation to edit for this event"));
return $this->redirectToRoute('chill_event__event_show',
return $this->redirectToRoute('chill_event__event_show',
array('event_id' => $event->getId()));
case 1:
// redirect to the form for a single participation
return $this->redirectToRoute('chill_event_participation_edit', array(
'participation_id' => $event->getParticipations()->current()->getId()
));
}
}
$form = $this->createEditFormMultiple($event->getParticipations(), $event);
return $this->render('ChillEventBundle:Participation:edit-multiple.html.twig', array(
'event' => $event,
'participations' => $event->getParticipations(),
'form' => $form->createView()
));
}
public function updateMultipleAction($event_id, Request $request)
{
/* @var $event \Chill\EventBundle\Entity\Event */
$event = $this->getDoctrine()->getRepository('ChillEventBundle:Event')
->find($event_id);
if ($event === null) {
throw $this->createNotFoundException("The event with id $event_id is not found");
}
$this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event, "You are not allowed "
. "to see this event");
foreach ($event->getParticipations() as $participation) {
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
$this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation,
"You are not allowed to update participation with id ".$participation->getId());
}
$form = $this->createEditFormMultiple($event->getParticipations(), $event);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->get('translator')->trans("The participations "
. "have been successfully updated."));
return $this->redirectToRoute('chill_event__event_show',
return $this->redirectToRoute('chill_event__event_show',
array('event_id' => $event->getId()));
}
return $this->render('ChillEventBundle:Participation:edit-multiple.html.twig', array(
'event' => $event,
'participations' => $event->getParticipations(),
'form' => $form->createView()
));
}
/**
* @param ArrayIterator $participations
* @param Event $event
@@ -679,14 +684,14 @@ class ParticipationController extends AbstractController
*/
protected function createEditFormMultiple(ArrayIterator $participations, Event $event)
{
$form = $this->createForm(\Symfony\Component\Form\Extension\Core\Type\FormType::class,
$form = $this->createForm(\Symfony\Component\Form\Extension\Core\Type\FormType::class,
array('participations' => $participations), array(
'method' => 'POST',
'action' => $this->generateUrl('chill_event_participation_update_multiple', array(
'event_id' => $event->getId()
))
));
$form->add('participations', CollectionType::class, array(
'entry_type' => ParticipationType::class,
'entry_options' => array(
@@ -694,14 +699,14 @@ class ParticipationController extends AbstractController
),
)
);
$form->add('submit', SubmitType::class, array(
'label' => 'Update'
));
return $form;
}
/**
* @param integer $participation_id
* @param Request $request
@@ -713,28 +718,28 @@ class ParticipationController extends AbstractController
$participation = $em->getRepository('ChillEventBundle:Participation')->findOneBy([
'id' => $participation_id
]);
if (! $participation) {
throw $this->createNotFoundException('Unable to find participation.');
}
/** @var Event $event */
$event = $participation->getEvent();
$form = $this->createDeleteForm($participation_id);
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
if ($form->isValid()) {
$em->remove($participation);
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans("The participation has been sucessfully removed")
);
return $this->redirectToRoute('chill_event__event_show', [
'event_id' => $event->getId()
]);
@@ -744,9 +749,9 @@ class ParticipationController extends AbstractController
'event_id' => $event->getId(),
'delete_form' => $form->createView()
]);
}
/**
* @param $participation_id
* @return \Symfony\Component\Form\FormInterface
@@ -762,5 +767,5 @@ class ParticipationController extends AbstractController
->getForm()
;
}
}

View File

@@ -46,7 +46,7 @@ class EventType
/**
* @var array
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
@@ -55,7 +55,7 @@ class EventType
* @ORM\Column(type="boolean")
*/
private $active;
/**
* @var Collection
* @ORM\OneToMany(

View File

@@ -44,7 +44,7 @@ class Role
/**
* @var array
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
@@ -53,7 +53,7 @@ class Role
* @ORM\Column(type="boolean")
*/
private $active;
/**
* @var EventType
* @ORM\ManyToOne(

View File

@@ -41,19 +41,19 @@ class Status
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var array
* @ORM\Column(type="json_array")
* @ORM\Column(type="json")
*/
private $name;
/**
* @var boolean
* @ORM\Column(type="boolean")
*/
private $active;
/**
* @var EventType
* @ORM\ManyToOne(

View File

@@ -504,6 +504,8 @@ class ApiController extends AbstractCRUDController
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity, [$postedData])
);
}
throw new \Exception('Unable to handle such request method.');
}
/**

View File

@@ -342,13 +342,19 @@ class CRUDController extends AbstractController
*/
protected function buildQueryEntities(string $action, Request $request)
{
return $this->getDoctrine()->getManager()
$query = $this->getDoctrine()->getManager()
->createQueryBuilder()
->select('e')
->from($this->getEntityClass(), 'e')
;
$this->customizeQuery($action, $request, $query);
return $query;
}
protected function customizeQuery(string $action, Request $request, $query): void {}
/**
* Query the entity.
*

View File

@@ -8,6 +8,7 @@ use Chill\MainBundle\Security\Authorization\ChillVoterInterface;
use Chill\MainBundle\Security\ProvideRoleInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\MainBundle\DependencyInjection\CompilerPass\SearchableServicesCompilerPass;
@@ -38,6 +39,8 @@ class ChillMainBundle extends Bundle
->addTag('chill_main.center_resolver');
$container->registerForAutoconfiguration(ScopeResolverInterface::class)
->addTag('chill_main.scope_resolver');
$container->registerForAutoconfiguration(ChillEntityRenderInterface::class)
->addTag('chill.render_entity');
$container->addCompilerPass(new SearchableServicesCompilerPass());
$container->addCompilerPass(new ConfigConsistencyCompilerPass());

View File

@@ -10,18 +10,18 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
*
* @author Julien Fastré <julien.fastre@champs-libres.coop
*
*
*/
class LoadCountriesCommand extends Command
{
/**
* @var EntityManager
*/
private $entityManager;
private $availableLanguages;
/**
* LoadCountriesCommand constructor.
*
@@ -34,7 +34,7 @@ class LoadCountriesCommand extends Command
$this->availableLanguages=$availableLanguages;
parent::__construct();
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::configure()
@@ -45,7 +45,7 @@ class LoadCountriesCommand extends Command
->setDescription('Load or update countries in db. This command does not delete existing countries, '.
'but will update names according to available languages');
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::execute()
@@ -54,43 +54,44 @@ class LoadCountriesCommand extends Command
{
$countries = static::prepareCountryList($this->availableLanguages);
$em = $this->entityManager;
foreach($countries as $country) {
$countryStored = $em->getRepository('ChillMainBundle:Country')
->findOneBy(array('countryCode' => $country->getCountryCode()));
if (NULL === $countryStored) {
$em->persist($country);
} else {
$countryStored->setName($country->getName());
}
}
$em->flush();
}
public static function prepareCountryList($languages)
{
$regionBundle = Intl::getRegionBundle();
$countries = [];
foreach ($languages as $language) {
$countries[$language] = $regionBundle->getCountryNames($language);
}
$countryEntities = array();
foreach ($countries[$languages[0]] as $countryCode => $name) {
$names = array();
foreach ($languages as $language) {
$names[$language] = $countries[$language][$countryCode];
}
$country = new \Chill\MainBundle\Entity\Country();
$country->setName($names)->setCountryCode($countryCode);
$countryEntities[] = $country;
}
return $countryEntities;
}
}

View File

@@ -3,6 +3,7 @@
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
/**
@@ -20,8 +21,17 @@ class AddressReferenceAPIController extends ApiController
$qb->where('e.postcode = :postal_code')
->setParameter('postal_code', $request->query->get('postal_code'));
}
}
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
{
$query->addOrderBy('e.street', 'ASC');
$query->addOrderBy('e.streetNumber', 'ASC');
return $query;
}
}

View File

@@ -41,4 +41,9 @@ class AdminController extends AbstractController
return $this->render('@ChillMain/Admin/layout_permissions.html.twig');
}
public function indexLocationsAction()
{
return $this->render('@ChillMain/Admin/layout_location.html.twig');
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
/**
* Class LocationApiController
*
* @package Chill\MainBundle\Controller
* @author Champs Libres
*/
class LocationApiController extends ApiController
{
public function customizeQuery(string $action, Request $request, $query): void
{
$query->andWhere($query->expr()->orX(
$query->expr()->andX(
$query->expr()->eq('e.createdBy', ':user'),
$query->expr()->gte('e.createdAt', ':dateBefore')
),
$query->expr()->andX(
$query->expr()->eq('e.availableForUsers', "'TRUE'"),
$query->expr()->eq('e.active', "'TRUE'"),
$query->expr()->isNotNull('e.name'),
$query->expr()->neq('e.name', ':emptyString'),
)
))
->setParameters([
'user' => $this->getUser(),
'dateBefore' => (new \DateTime())->sub(new \DateInterval('P6M')),
'emptyString' => '',
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Symfony\Component\HttpFoundation\Request;
class LocationController extends CRUDController
{
protected function customizeQuery(string $action, Request $request, $query): void
{
$query->where('e.availableForUsers = true'); //TODO not working
}
protected function createEntity(string $action, Request $request): object
{
$entity = parent::createEntity($action, $request);
$entity->setAvailableForUsers(true);
return $entity;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
/**
* Class LocationTypeApiController
*
* @package Chill\MainBundle\Controller
* @author Champs Libres
*/
class LocationTypeApiController extends ApiController
{
public function customizeQuery(string $action, Request $request, $query): void
{
$query->andWhere(
$query->expr()->andX(
$query->expr()->eq('e.availableForUsers', "'TRUE'"),
$query->expr()->eq('e.active', "'TRUE'"),
)
);
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
class LocationTypeController extends CRUDController
{
}

View File

@@ -24,26 +24,26 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface,
// Array of ancien languages (to exclude)
private $ancientToExclude = ["ang", "egy", "fro", "goh", "grc", "la", "non", "peo", "pro", "sga",
"dum", "enm", "frm", "gmh", "mga", "akk", "phn", "zxx", "got", "und"];
/**
*
*
* @var ContainerInterface
*/
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function getOrder() {
return 10;
}
public function load(ObjectManager $manager) {
echo "loading languages... \n";
foreach (Intl::getLanguageBundle()->getLanguageNames() as $code => $language) {
if (
!in_array($code, $this->regionalVersionToInclude)
@@ -58,23 +58,24 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface,
$manager->persist($lang);
}
}
$manager->flush();
}
/**
* prepare names for languages
*
* @param string $languageCode
* Prepare names for languages.
*
* @return string[] languages name indexed by available language code
*/
private function prepareName($languageCode) {
private function prepareName(string $languageCode): array {
$names = [];
foreach ($this->container->getParameter('chill_main.available_languages') as $lang) {
$names[$lang] = Intl::getLanguageBundle()->getLanguageName($languageCode);
}
return $names;
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace Chill\MainBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Entity\LocationType;
/**
* Load location types into database
*
* @author Champs Libres
*/
class LoadLocationType extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface {
/**
*
* @var ContainerInterface
*/
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function getOrder() {
return 52;
}
public function load(ObjectManager $manager): void {
echo "loading some location type... \n";
$arr = [
[
'name' => ['fr' => 'Mairie'],
'address_required' => LocationType::STATUS_OPTIONAL
],
[
'name' => ['fr' => 'Guichet d\'accueil'],
'address_required' => LocationType::STATUS_OPTIONAL
],
[
'name' => ['fr' => 'Domicile de l\'usager'],
'address_required' => LocationType::STATUS_REQUIRED
],
[
'name' => ['fr' => 'Centre d\'aide sociale'],
'address_required' => LocationType::STATUS_OPTIONAL
],
];
foreach ($arr as $a) {
$locationType = (new LocationType())
->setTitle($a['name'])
->setAvailableForUsers(true)
->setActive(true)
->setAddressRequired($a['address_required']);
$manager->persist($locationType);
}
$manager->flush();
}
}

View File

@@ -135,7 +135,6 @@ EOF;
85110,ST VINCENT STERLANGES,FR,85276,46.7397220689,-1.08371759277,INSEE
85110,SIGOURNAIS,FR,85282,46.7140097406,-0.98747730882,INSEE
85110,CHANTONNAY,FR,85051,46.6690167793,-1.04372588019,INSEE
85110,CHANTONNAY,FR,85051,46.6690167793,-1.04372588019,INSEE
85110,ST PROUANT,FR,85266,46.7502017421,-0.974504061491,INSEE
85120,LA CHAPELLE AUX LYS,FR,85053,46.6221916887,-0.642706103195,INSEE
85120,VOUVANT,FR,85305,46.5626835135,-0.764380170382,INSEE
@@ -156,11 +155,8 @@ EOF;
85130,ST AUBIN DES ORMEAUX,FR,85198,46.9958175597,-1.04216568722,INSEE
85140,ESSARTS EN BOCAGE,FR,85084,46.7806739038,-1.22925967851,INSEE
85140,LA MERLATIERE,FR,85142,46.7557703112,-1.29794577,INSEE
85140,ESSARTS EN BOCAGE,FR,85084,46.7806739038,-1.22925967851,INSEE
85140,ESSARTS EN BOCAGE,FR,85084,46.7806739038,-1.22925967851,INSEE
85140,ST MARTIN DES NOYERS,FR,85246,46.7239461187,-1.20379080965,INSEE
85140,CHAUCHE,FR,85064,46.8282791899,-1.27090860656,INSEE
85140,ESSARTS EN BOCAGE,FR,85084,46.7806739038,-1.22925967851,INSEE
85150,ST MATHURIN,FR,85250,46.5686332748,-1.70787622288,INSEE
85150,MARTINET,FR,85138,46.6620680463,-1.6772013304,INSEE
85150,STE FLAIVE DES LOUPS,FR,85211,46.611019489,-1.58031627863,INSEE
@@ -170,14 +166,12 @@ EOF;
85150,LE GIROUARD,FR,85099,46.5726064909,-1.58872487716,INSEE
85150,LANDERONDE,FR,85118,46.6549237031,-1.57351777893,INSEE
85150,LES ACHARDS,FR,85152,46.6163645636,-1.65038156849,INSEE
85150,LES ACHARDS,FR,85152,46.6163645636,-1.65038156849,INSEE
85150,VAIRE,FR,85298,46.6055340621,-1.74863672042,INSEE
85160,ST JEAN DE MONTS,FR,85234,46.8021968737,-2.04839789308,INSEE
85170,BELLEVIGNY,FR,85019,46.7756383534,-1.43313700054,INSEE
85170,LE POIRE SUR VIE,FR,85178,46.769919754,-1.50488626452,INSEE
85170,BEAUFOU,FR,85015,46.8191122027,-1.52479250801,INSEE
85170,DOMPIERRE SUR YON,FR,85081,46.7599858068,-1.37275519417,INSEE
85170,BELLEVIGNY,FR,85019,46.7756383534,-1.43313700054,INSEE
85170,LES LUCS SUR BOULOGNE,FR,85129,46.8527299002,-1.48398928084,INSEE
85170,ST DENIS LA CHEVASSE,FR,85208,46.8325959261,-1.3830312677,INSEE
85180,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
@@ -191,14 +185,11 @@ EOF;
85200,FONTENAY LE COMTE,FR,85092,46.4563186117,-0.793449510859,INSEE
85200,MERVENT,FR,85143,46.5325327351,-0.748519927998,INSEE
85200,DOIX LES FONTAINES,FR,85080,46.3849492327,-0.806840287485,INSEE
85200,FONTENAY LE COMTE,FR,85092,46.4563186117,-0.793449510859,INSEE
85200,LONGEVES,FR,85126,46.4722105292,-0.858917690239,INSEE
85200,ST MARTIN DE FRAIGNEAU,FR,85244,46.4289052087,-0.758948963227,INSEE
85200,SERIGNE,FR,85281,46.5054321828,-0.848819460581,INSEE
85200,BOURNEAU,FR,85033,46.5476882922,-0.813838020265,INSEE
85200,ST MICHEL LE CLOUCQ,FR,85256,46.4861591475,-0.743056336646,INSEE
85200,AUCHAY SUR VENDEE,FR,85009,46.4474386161,-0.876574265149,INSEE
85200,DOIX LES FONTAINES,FR,85080,46.3849492327,-0.806840287485,INSEE
85200,MONTREUIL,FR,85148,46.3973419593,-0.840846860992,INSEE
85200,L ORBRIE,FR,85167,46.4997145725,-0.77427886573,INSEE
85210,ST JEAN DE BEUGNE,FR,85233,46.5196817523,-1.10826075013,INSEE
@@ -238,12 +229,9 @@ EOF;
85260,LA COPECHAGNIERE,FR,85072,46.8523980181,-1.34349746898,INSEE
85260,L HERBERGEMENT,FR,85108,46.9166207979,-1.37033557148,INSEE
85260,MONTREVERD,FR,85197,46.9277672307,-1.4126154924,INSEE
85260,MONTREVERD,FR,85197,46.9277672307,-1.4126154924,INSEE
85260,MONTREVERD,FR,85197,46.9277672307,-1.4126154924,INSEE
85260,LES BROUZILS,FR,85038,46.8854235235,-1.33186892233,INSEE
85270,NOTRE DAME DE RIEZ,FR,85189,46.7532179022,-1.8935292542,INSEE
85270,ST HILAIRE DE RIEZ,FR,85226,46.7432732188,-1.96439228965,INSEE
85270,ST HILAIRE DE RIEZ,FR,85226,46.7432732188,-1.96439228965,INSEE
85280,LA FERRIERE,FR,85089,46.7215872927,-1.33469332327,INSEE
85290,MORTAGNE SUR SEVRE,FR,85151,46.9910941319,-0.946500033344,INSEE
85290,ST LAURENT SUR SEVRE,FR,85238,46.9506837971,-0.901123752328,INSEE
@@ -254,8 +242,6 @@ EOF;
85300,SALLERTAINE,FR,85280,46.8659054157,-1.94894081389,INSEE
85310,LA CHAIZE LE VICOMTE,FR,85046,46.6729533879,-1.29188591019,INSEE
85310,NESMY,FR,85160,46.5921936479,-1.40947698594,INSEE
85310,LA CHAIZE LE VICOMTE,FR,85046,46.6729533879,-1.29188591019,INSEE
85310,RIVES DE L YON,FR,85213,46.605637391,-1.3354497172,INSEE
85310,RIVES DE L YON,FR,85213,46.605637391,-1.3354497172,INSEE
85310,LE TABLIER,FR,85285,46.5596307281,-1.32788759657,INSEE
85320,CHATEAU GUIBERT,FR,85061,46.5741109302,-1.25524886228,INSEE
@@ -263,11 +249,9 @@ EOF;
85320,ROSNAY,FR,85193,46.5324344973,-1.3007139449,INSEE
85320,BESSAY,FR,85023,46.5397253861,-1.17028433093,INSEE
85320,LA BRETONNIERE LA CLAYE,FR,85036,46.4879459421,-1.26773426545,INSEE
85320,LA BRETONNIERE LA CLAYE,FR,85036,46.4879459421,-1.26773426545,INSEE
85320,CORPE,FR,85073,46.5050234767,-1.17034425311,INSEE
85320,MAREUIL SUR LAY DISSAIS,FR,85135,46.5335825488,-1.22688907859,INSEE
85320,PEAULT,FR,85171,46.502029199,-1.22708559855,INSEE
85320,MAREUIL SUR LAY DISSAIS,FR,85135,46.5335825488,-1.22688907859,INSEE
85320,LA COUTURE,FR,85074,46.523938732,-1.26493227292,INSEE
85320,MOUTIERS SUR LE LAY,FR,85157,46.5651677306,-1.16826489836,INSEE
85320,STE PEXINE,FR,85261,46.5596018797,-1.12406235901,INSEE
@@ -275,7 +259,6 @@ EOF;
85340,L ILE D OLONNE,FR,85112,46.570163703,-1.7737502368,INSEE
85340,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
85350,L ILE D YEU,FR,85113,46.7093514816,-2.34712702345,INSEE
85350,L ILE D YEU,FR,85113,46.7093514816,-2.34712702345,INSEE
85360,LA TRANCHE SUR MER,FR,85294,46.3564601605,-1.43136322126,INSEE
85370,MOUZEUIL ST MARTIN,FR,85158,46.4591118412,-0.984449849889,INSEE
85370,NALLIERS,FR,85159,46.4658962703,-1.03958611312,INSEE
@@ -286,7 +269,6 @@ EOF;
85390,CHAVAGNES LES REDOUX,FR,85066,46.7101499475,-0.915900131393,INSEE
85390,CHEFFOIS,FR,85067,46.6786935635,-0.782949851125,INSEE
85390,MOUILLERON ST GERMAIN,FR,85154,46.6612700667,-0.846784201071,INSEE
85390,MOUILLERON ST GERMAIN,FR,85154,46.6612700667,-0.846784201071,INSEE
85400,STE GEMME LA PLAINE,FR,85216,46.4732196212,-1.11103084694,INSEE
85400,LAIROUX,FR,85117,46.4496842668,-1.27114022202,INSEE
85400,LUCON,FR,85128,46.4510564854,-1.16449285012,INSEE
@@ -294,7 +276,6 @@ EOF;
85400,CHASNAIS,FR,85058,46.4459908481,-1.2385924923,INSEE
85410,ST LAURENT DE LA SALLE,FR,85237,46.5854041653,-0.922177315485,INSEE
85410,LA CAILLERE ST HILAIRE,FR,85040,46.6293907412,-0.933153931505,INSEE
85410,LA CAILLERE ST HILAIRE,FR,85040,46.6293907412,-0.933153931505,INSEE
85410,ST CYR DES GATS,FR,85205,46.572397925,-0.86344873853,INSEE
85410,THOUARSAIS BOUILDROUX,FR,85292,46.6062740621,-0.873461023865,INSEE
85410,CEZAIS,FR,85041,46.5917363748,-0.802618133558,INSEE
@@ -310,20 +291,16 @@ EOF;
85420,RIVES D AUTISE,FR,85162,46.424726987,-0.665995249042,INSEE
85430,AUBIGNY LES CLOUZEAUX,FR,85008,46.6028241769,-1.46743549114,INSEE
85430,NIEUL LE DOLENT,FR,85161,46.5676509922,-1.51560194548,INSEE
85430,AUBIGNY LES CLOUZEAUX,FR,85008,46.6028241769,-1.46743549114,INSEE
85430,LA BOISSIERE DES LANDES,FR,85026,46.5581861734,-1.44371985689,INSEE
85440,ST HILAIRE LA FORET,FR,85231,46.4551155186,-1.53048160541,INSEE
85440,TALMONT ST HILAIRE,FR,85288,46.475786445,-1.62751498166,INSEE
85440,POIROUX,FR,85179,46.5107890457,-1.53929317556,INSEE
85440,GROSBREUIL,FR,85103,46.5390090882,-1.6072005484,INSEE
85440,AVRILLE,FR,85010,46.4744272125,-1.49524360118,INSEE
85440,TALMONT ST HILAIRE,FR,85288,46.475786445,-1.62751498166,INSEE
85450,CHAMPAGNE LES MARAIS,FR,85049,46.3735020647,-1.13380723653,INSEE
85450,LA TAILLEE,FR,85286,46.3852513569,-0.941017792066,INSEE
85450,CHAILLE LES MARAIS,FR,85042,46.3853555319,-1.01044079362,INSEE
85450,CHAILLE LES MARAIS,FR,85042,46.3853555319,-1.01044079362,INSEE
85450,VOUILLE LES MARAIS,FR,85304,46.3891941167,-0.968106001439,INSEE
85450,CHAILLE LES MARAIS,FR,85042,46.3853555319,-1.01044079362,INSEE
85450,MOREILLES,FR,85149,46.4218721314,-1.09404530407,INSEE
85450,PUYRAVAULT,FR,85185,46.3653834101,-1.09115660367,INSEE
85450,STE RADEGONDE DES NOYERS,FR,85267,46.3694246909,-1.06671995264,INSEE
@@ -331,14 +308,10 @@ EOF;
85460,L AIGUILLON SUR MER,FR,85001,46.304138479,-1.2623239198,INSEE
85470,BRETIGNOLLES SUR MER,FR,85035,46.6374826705,-1.86324200464,INSEE
85470,BREM SUR MER,FR,85243,46.6118566989,-1.81003917923,INSEE
85470,BREM SUR MER,FR,85243,46.6118566989,-1.81003917923,INSEE
85480,BOURNEZEAU,FR,85034,46.6296975315,-1.14101742229,INSEE
85480,FOUGERE,FR,85093,46.6617881911,-1.23612691916,INSEE
85480,ST HILAIRE LE VOUHIS,FR,85232,46.6859198669,-1.15222590884,INSEE
85480,THORIGNY,FR,85291,46.6179795025,-1.24888057642,INSEE
85480,BOURNEZEAU,FR,85034,46.6296975315,-1.14101742229,INSEE
85490,BENET,FR,85020,46.368873213,-0.613959918706,INSEE
85490,BENET,FR,85020,46.368873213,-0.613959918706,INSEE
85490,BENET,FR,85020,46.368873213,-0.613959918706,INSEE
85500,BEAUREPAIRE,FR,85017,46.9050210355,-1.10144867013,INSEE
85500,ST PAUL EN PAREDS,FR,85259,46.8303789022,-0.964515191283,INSEE
@@ -356,12 +329,10 @@ EOF;
85540,ST VINCENT SUR GRAON,FR,85277,46.5034756656,-1.382954206,INSEE
85540,LA JONCHERE,FR,85116,46.4358647401,-1.38517843312,INSEE
85540,ST BENOIST SUR MER,FR,85201,46.4266286403,-1.3399129604,INSEE
85540,ST VINCENT SUR GRAON,FR,85277,46.5034756656,-1.382954206,INSEE
85540,CURZON,FR,85077,46.4512376923,-1.30138059216,INSEE
85540,ST AVAUGOURD DES LANDES,FR,85200,46.5136722903,-1.47528120789,INSEE
85540,ST CYR EN TALMONDAIS,FR,85206,46.4597334032,-1.33722144355,INSEE
85550,LA BARRE DE MONTS,FR,85012,46.8722784154,-2.09984018879,INSEE
85550,LA BARRE DE MONTS,FR,85012,46.8722784154,-2.09984018879,INSEE
85560,LE BERNARD,FR,85022,46.44832528,-1.43979865314,INSEE
85560,LONGEVILLE SUR MER,FR,85127,46.4091029013,-1.47711855345,INSEE
85570,POUILLE,FR,85181,46.5022256779,-0.955223380119,INSEE
@@ -381,11 +352,7 @@ EOF;
85590,ST MARS LA REORTHE,FR,85242,46.8597253005,-0.925777900202,INSEE
85600,LA BOISSIERE DE MONTAIGU,FR,85025,46.9451858636,-1.1916392484,INSEE
85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE
85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE
85600,TREIZE SEPTIERS,FR,85295,46.9975586143,-1.23193361154,INSEE
85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE
85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE
85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE
85610,CUGAND,FR,85076,47.0602388146,-1.25289811103,INSEE
85610,LA BERNARDIERE,FR,85021,47.0361828072,-1.27390355206,INSEE
85620,ROCHESERVIERE,FR,85190,46.9274273036,-1.50132208111,INSEE
@@ -406,11 +373,8 @@ EOF;
85700,MONTOURNAIS,FR,85147,46.7502937556,-0.770013941158,INSEE
85700,POUZAUGES,FR,85182,46.7812581702,-0.828778359084,INSEE
85700,REAUMUR,FR,85187,46.7145137269,-0.816742537248,INSEE
85700,SEVREMONT,FR,85090,46.8211105864,-0.854584153953,INSEE
85700,MENOMBLET,FR,85141,46.7301338667,-0.728654955878,INSEE
85700,ST MESMIN,FR,85254,46.8005779435,-0.748892533741,INSEE
85700,SEVREMONT,FR,85090,46.8211105864,-0.854584153953,INSEE
85700,SEVREMONT,FR,85090,46.8211105864,-0.854584153953,INSEE
85710,BOIS DE CENE,FR,85024,46.9479643351,-1.89668693466,INSEE
85710,CHATEAUNEUF,FR,85062,46.916944435,-1.9261131832,INSEE
85710,LA GARNACHE,FR,85096,46.8977541296,-1.82443040539,INSEE
@@ -420,10 +384,9 @@ EOF;
85770,VIX,FR,85303,46.3543018169,-0.856628326667,INSEE
85770,LE GUE DE VELLUIRE,FR,85105,46.3675950645,-0.905432724485,INSEE
85770,L ILE D ELLE,FR,85111,46.3334258655,-0.919100677098,INSEE
85770,LES VELLUIRE SUR VENDEE,FR,85177,46.4190919441,-0.910475769222,INSEE
85800,ST GILLES CROIX DE VIE,FR,85222,46.6904708814,-1.91946363327,INSEE
85800,LE FENOUILLER,FR,85088,46.7161264566,-1.89206667498,INSEE
85800,GIVRAND,FR,85100,46.6822701061,-1.8787272243,INSEE
85800,GIVRAND,FR,85100,46.6822701061,-1.8787272243,INSEE
EOF;
}

View File

@@ -20,7 +20,10 @@
namespace Chill\MainBundle\DependencyInjection;
use Chill\MainBundle\Controller\AddressApiController;
use Chill\MainBundle\Controller\LocationController;
use Chill\MainBundle\Controller\LocationTypeController;
use Chill\MainBundle\Controller\UserController;
use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength;
use Chill\MainBundle\Doctrine\DQL\STContains;
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
use Chill\MainBundle\Entity\User;
@@ -44,6 +47,10 @@ use Chill\MainBundle\Doctrine\DQL\Replace;
use Chill\MainBundle\Doctrine\ORM\Hydration\FlatHierarchyEntityHydrator;
use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
use Chill\MainBundle\Doctrine\Type\PointType;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\LocationType;
use Chill\MainBundle\Form\LocationTypeType;
use Chill\MainBundle\Form\LocationFormType;
use Symfony\Component\HttpFoundation\Request;
/**
@@ -90,12 +97,19 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
// replace all config with a main key:
$container->setParameter('chill_main', $config);
// legacy config
$container->setParameter('chill_main.installation_name',
$config['installation_name']);
$container->setParameter('chill_main.available_languages',
$config['available_languages']);
$container->setParameter('chill_main.available_countries',
$config['available_countries']);
$container->setParameter('chill_main.routing.resources',
$config['routing']['resources']);
@@ -193,6 +207,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'OVERLAPSI' => OverlapsI::class,
'STRICT_WORD_SIMILARITY_OPS' => StrictWordSimilarityOPS::class,
'ST_CONTAINS' => STContains::class,
'JSONB_ARRAY_LENGTH' => JsonbArrayLength::class,
],
],
'hydrators' => [
@@ -315,7 +330,51 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'template' => '@ChillMain/User/edit.html.twig'
]
]
]
],
[
'class' => Location::class,
'name' => 'main_location',
'base_path' => '/admin/main/location',
'base_role' => 'ROLE_ADMIN',
'form_class' => LocationFormType::class,
'controller' => LocationController::class,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Location/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Location/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Location/edit.html.twig',
]
]
],
[
'class' => LocationType::class,
'name' => 'main_location_type',
'base_path' => '/admin/main/location-type',
'base_role' => 'ROLE_ADMIN',
'form_class' => LocationTypeType::class,
'controller' => LocationTypeController::class,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/LocationType/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/LocationType/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/LocationType/edit.html.twig',
]
]
],
],
'apis' => [
[
@@ -445,6 +504,51 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
],
]
],
[
'class' => \Chill\MainBundle\Entity\Location::class,
'controller' => \Chill\MainBundle\Controller\LocationApiController::class,
'name' => 'location',
'base_path' => '/api/1.0/main/location',
'base_role' => 'ROLE_USER',
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
Request::METHOD_POST => true,
]
],
]
],
[
'class' => \Chill\MainBundle\Entity\LocationType::class,
'controller' => \Chill\MainBundle\Controller\LocationTypeApiController::class,
'name' => 'location_type',
'base_path' => '/api/1.0/main/location-type',
'base_role' => 'ROLE_USER',
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
]
],
]
]
]
]);
}

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