From c0ee51068cf09f093168ae1967107e25b4517f26 Mon Sep 17 00:00:00 2001 From: nobohan Date: Thu, 7 Apr 2022 16:55:54 +0200 Subject: [PATCH 01/23] avoid address reference search on undefined post code --- CHANGELOG.md | 1 + .../vuejs/Address/components/AddAddress/AddressSelection.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c278ca93e..ddc97b7b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to ## Unreleased +* [main] avoid address reference search on undefined post code (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/561) * [main] notification toggle read: correct js syntax for compilation in production (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/548) * [parcours] Display of interlocuteurs changed to flex-table in parcours edit page to prevent cut-off of information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/535) * [activity] espace entre les boutons pour supprimer les documents diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue index 18e0caca3..2c8e17687 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue @@ -119,7 +119,7 @@ export default { }, listenInputSearch(query) { //console.log('listenInputSearch', query, this.isAddressSelectorOpen); - if (!this.entity.selected.writeNew.postcode) { + if (!this.entity.selected.writeNew.postcode && 'id' in this.entity.selected.city) { if (query.length > 2) { this.isLoading = true; searchReferenceAddresses(query, this.entity.selected.city).then( From 07ea2b771c8581066e164ba0a0390c59fd38d744 Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 22 Apr 2022 16:37:21 +0200 Subject: [PATCH 02/23] person: add validation to relationship to avoid duplicate --- .../Entity/Relationships/Relationship.php | 2 + .../Relationship/RelationshipNoDuplicate.php | 27 +++++++++ .../RelationshipNoDuplicateValidator.php | 56 +++++++++++++++++++ .../translations/validators.fr.yml | 4 ++ 4 files changed, 89 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicate.php create mode 100644 src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicateValidator.php diff --git a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php index d51881bb2..62fbb63a9 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php +++ b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php @@ -15,6 +15,7 @@ use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Validator\Constraints\Relationship\RelationshipNoDuplicate; use DateTimeImmutable; use DateTimeInterface; use Doctrine\ORM\Mapping as ORM; @@ -31,6 +32,7 @@ use Symfony\Component\Validator\Constraints as Assert; * @DiscriminatorMap(typeProperty="type", mapping={ * "relationship": Relationship::class * }) + * @RelationshipNoDuplicate */ class Relationship implements TrackCreationInterface, TrackUpdateInterface { diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicate.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicate.php new file mode 100644 index 000000000..db4d7c0d6 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicate.php @@ -0,0 +1,27 @@ +relationshipRepository = $relationshipRepository; + } + + public function validate($relationship, Constraint $constraint) + { + if (!$constraint instanceof RelationshipNoDuplicate) { + throw new UnexpectedTypeException($constraint, RelationshipNoDuplicate::class); + } + + $fromPerson = $relationship->getFromPerson(); + $toPerson = $relationship->getToPerson(); + + $relationships = $this->relationshipRepository->findBy([ + 'fromPerson' => $fromPerson, + 'fromPerson' => $toPerson, + 'toPerson' => $fromPerson, + 'toPerson' => $fromPerson, + ]); + + foreach ($relationships as $r) { + if ( + $r->getFromPerson() === $fromPerson + || $r->getFromPerson() === $toPerson + || $r->getToPerson() === $fromPerson + || $r->getToPerson() === $toPerson + ) { + $this->context->buildViolation($constraint->message) + ->addViolation(); + } + } + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml index 13fcb54fb..b2bc549d7 100644 --- a/src/Bundle/ChillPersonBundle/translations/validators.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/validators.fr.yml @@ -62,3 +62,7 @@ You cannot associate a resource with the same person: Vous ne pouvez pas ajouter #location The period must remain located: 'Un parcours doit être localisé' The person where the course is located must be associated to the course. Change course's location before removing the person.: "Le parcours est localisé auprès cet usager. Veuillez changer la localisation du parcours avant de suprimer l'usager" + +#relationship +relationship: + duplicate: Une relation de filiation existe déjà entre ces 2 personnes \ No newline at end of file From 5acd49357e39ec955ab82dc0292f8402e59b3c54 Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 22 Apr 2022 17:22:56 +0200 Subject: [PATCH 03/23] person: add validation on relationship between person --- .../Resources/public/vuejs/VisGraph/App.vue | 28 ++++++---- .../Resources/public/vuejs/VisGraph/api.js | 51 ++----------------- .../Resources/public/vuejs/VisGraph/index.js | 10 +++- 3 files changed, 31 insertions(+), 58 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue index f5db187b9..f86c68576 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/App.vue @@ -472,15 +472,25 @@ export default { case 'create': return postRelationship(this.modal.data) - .then(relationship => new Promise(resolve => { - //console.log('post relationship response', relationship) - this.$store.dispatch('addLinkFromRelationship', relationship) - this.modal.showModal = false - this.resetForm() - this.forceUpdateComponent() - resolve() - })) - .catch() + .then(relationship => new Promise(resolve => { + //console.log('post relationship response', relationship) + this.$store.dispatch('addLinkFromRelationship', relationship) + this.modal.showModal = false + this.resetForm() + this.forceUpdateComponent() + resolve() + })) + .catch( error => { + if (error.name === 'ValidationException') { + for (let v of error.violations) { + this.$toast.open({message: v }); + console.log(v) + } + } else { + this.$toast.open({message: 'An error occurred'}); + } + } + ) case 'edit': return patchRelationship(this.modal.data) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js index 448ff6633..01c335436 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/api.js @@ -1,50 +1,5 @@ -import { splitId } from './vis-network' - -/** - * @function makeFetch - * @param method - * @param url - * @param body - * @returns {Promise} - */ -const makeFetch = (method, url, body) => { - return fetch(url, { - method: method, - headers: { - 'Content-Type': 'application/json;charset=utf-8' - }, - body: (body !== null) ? JSON.stringify(body) : null - }) - .then(response => { - - if (response.ok) { - return response.json(); - } - - if (response.status === 422) { - return response.json().then(violations => { - throw ValidationException(violations) - }); - } - - throw { - msg: 'Error while updating AccompanyingPeriod Course.', - sta: response.status, - txt: response.statusText, - err: new Error(), - body: response.body - }; - }); -} - -/** - * @param violations - * @constructor - */ -const ValidationException = (violations) => { - this.violations = violations - this.name = 'ValidationException' -} +import { splitId } from './vis-network'; +import {makeFetch} from 'ChillMainAssets/lib/api/apiMethods.js'; /** * @function getFetch @@ -136,7 +91,7 @@ const getRelationsList = () => { * @returns {Promise} */ const postRelationship = (relationship) => { - //console.log(relationship) + //console.log(relationship); return postFetch( `/api/1.0/relations/relationship.json`, { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js index 5e8989e49..a64afd4a1 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/VisGraph/index.js @@ -3,8 +3,10 @@ import { store } from "./store.js" import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n' import { visMessages } from './i18n' import App from './App.vue' +import VueToast from 'vue-toast-notification'; +import 'vue-toast-notification/dist/theme-sugar.css'; -import './vis-network' +import './vis-network'; const i18n = _createI18n(visMessages) const container = document.getElementById('relationship-graph') @@ -25,5 +27,11 @@ const app = createApp({ }) .use(store) .use(i18n) +.use(VueToast, { + position: "bottom-right", + type: "error", + duration: 5000, + dismissible: true + }) .component('app', App) .mount('#relationship-graph') From 63dacb9ebbba660a209688d7f17b88a37ed78528 Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 22 Apr 2022 17:24:29 +0200 Subject: [PATCH 04/23] upd CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c1c3d1f..64574ff5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to ## Unreleased +* [person] prevent duplicate relationship in filiation/household graph (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/560) + * [Activity form] invert 'incoming' and 'receiving' in Activity form * [Activity form] keep the same order for 'attendee' field in new and edit form * [list with period] use "sameas" test operator to introduce requestor in list @@ -24,7 +26,7 @@ and this project adheres to * [Accompanying period work evaluations] list documents associated to a work by creation date, and then by id, from the most recent to older * [Course comment] add validationConstraint NotNull and NotBlank on comment content, to avoid sql error * [Notifications] delay the sending of notificaiton to kernel.terminate -* [Notifications / Period user change] fix the sending of notification when user changes +* [Notifications / Period user change] fix the sending of notification when user changes ## Test releases From 09503768f56f9e014fc94b232b154bc838e9996b Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 25 Apr 2022 10:28:51 +0200 Subject: [PATCH 05/23] unpin comment is possible + delete and edit by all users that can edit period --- .../AccompanyingCourseCommentController.php | 22 +++++++++++++++++-- .../Comment/index.html.twig | 15 +++++++++++-- .../translations/messages.fr.yml | 2 ++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php index be6bcab07..3a77434d2 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php @@ -84,7 +84,7 @@ class AccompanyingCourseCommentController extends AbstractController } if (isset($commentEdited)) { - $this->denyAccessUnlessGranted(AccompanyingPeriodCommentVoter::EDIT, $commentEdited); + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $commentEdited->getAccompanyingPeriod()); } else { throw new LogicException('at this step, commentEdited should be set'); } @@ -135,7 +135,7 @@ class AccompanyingCourseCommentController extends AbstractController */ public function deleteAction(AccompanyingPeriod\Comment $comment, Request $request): Response { - $this->denyAccessUnlessGranted(AccompanyingPeriodCommentVoter::DELETE, $comment); + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $comment->getAccompanyingPeriod()); $form = $this->createForm(FormType::class, []); $form->add('submit', SubmitType::class, ['label' => 'Confirm']); @@ -186,6 +186,24 @@ class AccompanyingCourseCommentController extends AbstractController ]); } + /** + * @Route("/{_locale}/parcours/comment/{id}/unpin", name="chill_person_accompanying_period_comment_unpin") + */ + public function unpinComment(AccompanyingPeriod\Comment $comment): Response + { + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $comment->getAccompanyingPeriod()); + + $comment->getAccompanyingPeriod()->setPinnedComment(null); + + $this->getDoctrine()->getManager()->flush(); + + $this->addFlash('success', $this->translator->trans('accompanying_course.comment is unpinned')); + + return $this->redirectToRoute('chill_person_accompanying_period_comment_list', [ + 'accompanying_period_id' => $comment->getAccompanyingPeriod()->getId(), + ]); + } + private function createCommentForm(AccompanyingPeriod\Comment $comment, string $step): FormInterface { return $this->formFactory->createNamed($step, AccompanyingCourseCommentType::class, $comment); diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/Comment/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/Comment/index.html.twig index d5ece68a9..47238fa9d 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/Comment/index.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/Comment/index.html.twig @@ -8,6 +8,17 @@ {% macro recordAction(comment, isPinned) %} {% if isPinned is defined and isPinned == true %} +
  • +
    + +
    +
  • {% else %}
  • @@ -17,7 +28,7 @@
  • {% endif %} - {% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_COMMENT_EDIT', comment) %} + {% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_UPDATE', comment.accompanyingPeriod) %}
  • {% endif %} - {% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_COMMENT_DELETE', comment) %} + {% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_UPDATE', comment.accompanyingPeriod) %}
  • diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 2a4077e1c..985804f6c 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -465,12 +465,14 @@ fix it: Compléter accompanying_course: administrative_location: Localisation administrative comment is pinned: Le commentaire est épinglé + comment is unpinned: Le commentaire est désépinglé # Accompanying Course comments Accompanying Course Comment: Commentaire Accompanying Course Comment list: Commentaires du parcours pinned: épinglé Pin comment: Épingler +Unpin comment: Désépingler Post a new comment: Poster un nouveau commentaire Write a new comment: Écrire un nouveau commentaire Edit a comment: Modifier le commentaire From 79e46c7fe801e058cf0e49c5851ea794ec9b3468 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 25 Apr 2022 10:30:44 +0200 Subject: [PATCH 06/23] changelog updated --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c1c3d1f..b99d776ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,8 @@ and this project adheres to * [Accompanying period work evaluations] list documents associated to a work by creation date, and then by id, from the most recent to older * [Course comment] add validationConstraint NotNull and NotBlank on comment content, to avoid sql error * [Notifications] delay the sending of notificaiton to kernel.terminate -* [Notifications / Period user change] fix the sending of notification when user changes +* [Notifications / Period user change] fix the sending of notification when user changes +* [parcours]: Comments can be unpinned + edit/delete for all users that are allowed to edit parcours (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/566) ## Test releases From f5efb07e3cbd559344f968833aa4e2884e5d690c Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Mon, 25 Apr 2022 10:32:02 +0200 Subject: [PATCH 07/23] csfixes --- .../Controller/AccompanyingCourseCommentController.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php index 3a77434d2..06bfe95ff 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php @@ -13,7 +13,6 @@ namespace Chill\PersonBundle\Controller; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Form\AccompanyingCourseCommentType; -use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; use LogicException; From 111906c2b9599fd99c3f5801811e7aea840b9116 Mon Sep 17 00:00:00 2001 From: nobohan Date: Mon, 25 Apr 2022 11:23:28 +0200 Subject: [PATCH 08/23] person: add unique index on table relationship to avoid duplicate fromperson_id/toperson_id pairs --- .../migrations/Version20220425000000.php | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php b/src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php new file mode 100644 index 000000000..2feb246bd --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php @@ -0,0 +1,37 @@ +addSql('DROP INDEX IDX_RELATIONSHIPS000'); + } + + public function getDescription(): string + { + return 'Add constraint with a index on chill_person_relationships.'; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE UNIQUE INDEX IDX_RELATIONSHIPS000 ON chill_person_relationships (least(fromperson_id, toperson_id), greatest(fromperson_id, toperson_id))'); + } +} + From 3ad8223949eebd06c8fc9477c6bd4c05a52a9dc1 Mon Sep 17 00:00:00 2001 From: nobohan Date: Mon, 25 Apr 2022 11:24:29 +0200 Subject: [PATCH 09/23] person: add unique index on table relationship to avoid duplicate fromperson_id/toperson_id pairs - typo cs fixer --- .../ChillPersonBundle/migrations/Version20220425000000.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php b/src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php index 2feb246bd..1dd50d224 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20220425000000.php @@ -34,4 +34,3 @@ final class Version20220425000000 extends AbstractMigration $this->addSql('CREATE UNIQUE INDEX IDX_RELATIONSHIPS000 ON chill_person_relationships (least(fromperson_id, toperson_id), greatest(fromperson_id, toperson_id))'); } } - From f8410de569f96645fb3d1ee5fe29655e00f41863 Mon Sep 17 00:00:00 2001 From: nobohan Date: Mon, 25 Apr 2022 11:34:17 +0200 Subject: [PATCH 10/23] person: correct relationship no duplicate validator --- .../Relationship/RelationshipNoDuplicateValidator.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicateValidator.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicateValidator.php index 0a326df36..580fc4b48 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicateValidator.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Relationship/RelationshipNoDuplicateValidator.php @@ -35,10 +35,8 @@ class RelationshipNoDuplicateValidator extends ConstraintValidator $toPerson = $relationship->getToPerson(); $relationships = $this->relationshipRepository->findBy([ - 'fromPerson' => $fromPerson, - 'fromPerson' => $toPerson, - 'toPerson' => $fromPerson, - 'toPerson' => $fromPerson, + 'fromPerson' => [$fromPerson, $toPerson], + 'toPerson' => [$fromPerson, $toPerson], ]); foreach ($relationships as $r) { From 51d1e5422b1a027d19f4000ab5ac4b203bc298fe Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 26 Apr 2022 10:27:45 +0200 Subject: [PATCH 11/23] remove unnecessary code --- src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 7615e59fe..20156e4c4 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -1258,9 +1258,6 @@ class AccompanyingPeriod implements */ public function setPinnedComment(?Comment $comment = null): self { - if (null !== $this->pinnedComment) { - $this->removeComment($this->pinnedComment); - } if (null !== $this->pinnedComment) { $this->addComment($this->pinnedComment); From 2684345981cd2b3a724767bc804184b132f9b984 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Tue, 26 Apr 2022 11:34:49 +0200 Subject: [PATCH 12/23] voter updates --- .../AccompanyingCourseCommentController.php | 5 +++-- .../Authorization/AccompanyingPeriodCommentVoter.php | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php index 06bfe95ff..09af4a3cf 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php @@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Controller; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Form\AccompanyingCourseCommentType; +use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Doctrine\ORM\EntityManagerInterface; use LogicException; @@ -83,7 +84,7 @@ class AccompanyingCourseCommentController extends AbstractController } if (isset($commentEdited)) { - $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $commentEdited->getAccompanyingPeriod()); + $this->denyAccessUnlessGranted(AccompanyingPeriodCommentVoter::EDIT, $commentEdited); } else { throw new LogicException('at this step, commentEdited should be set'); } @@ -134,7 +135,7 @@ class AccompanyingCourseCommentController extends AbstractController */ public function deleteAction(AccompanyingPeriod\Comment $comment, Request $request): Response { - $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $comment->getAccompanyingPeriod()); + $this->denyAccessUnlessGranted(AccompanyingPeriodCommentVoter::DELETE, $comment); $form = $this->createForm(FormType::class, []); $form->add('submit', SubmitType::class, ['label' => 'Confirm']); diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php index 37a6ec6ac..64fdbb796 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php @@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Security\Authorization; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; +use Symfony\Component\Security\Core\Security; use UnexpectedValueException; class AccompanyingPeriodCommentVoter extends Voter @@ -22,6 +23,13 @@ class AccompanyingPeriodCommentVoter extends Voter public const EDIT = 'CHILL_PERSON_ACCOMPANYING_PERIOD_COMMENT_EDIT'; + private Security $security; + + public function __construct(Security $security) + { + $this->security = $security; + } + protected function supports($attribute, $subject) { return $subject instanceof Comment; @@ -32,9 +40,9 @@ class AccompanyingPeriodCommentVoter extends Voter /** @var Comment $subject */ switch ($attribute) { case self::EDIT: + return $this->security->isGranted(AccompanyingPeriodVoter::EDIT, $subject->getAccompanyingPeriod()); case self::DELETE: - return $subject->getCreator() === $token->getUser(); - + return $this->security->isGranted(AccompanyingPeriodVoter::EDIT, $subject->getAccompanyingPeriod()); default: throw new UnexpectedValueException("This attribute {$attribute} is not supported"); } From 76549581e67e0bac890fcc869a40e4eb1cf8c12b Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 27 Apr 2022 10:38:25 +0200 Subject: [PATCH 13/23] address: fix bug when editing address: update localisation and addressreferenceId + better update of the map in edition --- .../vuejs/Address/components/AddAddress.vue | 4 +++ .../components/AddAddress/AddressMap.vue | 30 +++++++++++-------- .../components/AddAddress/CitySelection.vue | 3 ++ .../Normalizer/AddressNormalizer.php | 1 + 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue index e351109a8..fcd64ed70 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue @@ -628,6 +628,10 @@ export default { newAddress = Object.assign(newAddress, { 'addressReference': this.entity.selected.address.addressReference }); + } else { + newAddress = Object.assign(newAddress, { + 'addressReference': null + }); } if (this.validFrom) { diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMap.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMap.vue index c6abd92d5..80d2ca01a 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMap.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressMap.vue @@ -8,12 +8,15 @@ import L from 'leaflet'; import markerIconPng from 'leaflet/dist/images/marker-icon.png' import 'leaflet/dist/leaflet.css'; -let map; -let marker; - export default { name: 'AddressMap', props: ['entity'], + data() { + return { + map: null, + marker: null + } + }, computed: { center() { return this.entity.selected.addressMap.center; @@ -21,30 +24,33 @@ export default { }, methods:{ init() { - map = L.map('address_map').setView([46.67059, -1.42683], 12); + this.map = L.map('address_map').setView([46.67059, -1.42683], 12); - map.scrollWheelZoom.disable(); + this.map.scrollWheelZoom.disable(); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' - }).addTo(map); + }).addTo(this.map); const markerIcon = L.icon({ iconUrl: markerIconPng, iconAnchor: [12, 41], }); - marker = L.marker([48.8589, 2.3469], {icon: markerIcon}).addTo(map); - + this.marker = L.marker([48.8589, 2.3469], {icon: markerIcon}); + this.marker.addTo(this.map); }, update() { - //console.log('update map with : ', this.address.addressMap.center) - marker.setLatLng(this.entity.addressMap.center); - map.setView(this.entity.addressMap.center, 15); + //console.log('update map with : ', this.entity.addressMap.center) + if (this.marker && this.entity.addressMap.center) { + this.marker.setLatLng(this.entity.addressMap.center); + this.map.setView(this.entity.addressMap.center, 15); + } } }, mounted(){ - this.init() + this.init(); + this.update(); } } diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue index ca5d01b50..9dd85fa73 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue @@ -106,6 +106,9 @@ export default { this.$emit('getReferenceAddresses', this.value); if (this.value.center) { this.updateMapCenter(this.value.center); + if (this.value.center.coordinates) { + this.entity.selected.postcode.coordinates = this.value.center.coordinates; + } } } }, diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php index ccb48c160..0809863f6 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php @@ -71,6 +71,7 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw 'id' => $address->getPostCode()->getId(), 'name' => $address->getPostCode()->getName(), 'code' => $address->getPostCode()->getCode(), + 'center' => $address->getPostcode()->getCenter(), ], 'country' => [ 'id' => $address->getPostCode()->getCountry()->getId(), From 6662e0fb5f9bfeb8fa3896bfb9bafdc25aa8d28a Mon Sep 17 00:00:00 2001 From: nobohan Date: Wed, 27 Apr 2022 10:40:11 +0200 Subject: [PATCH 14/23] upd CHANGELOG --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ea16e7fc..c517623e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to ## Unreleased +* [address] fix bug when editing address: update location and addressreferenceId + better update of the map in edition (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/593) + * [Documents] Validate storedObject and allow for null data (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/565) * [Activity form] invert 'incoming' and 'receiving' in Activity form * [Activity form] keep the same order for 'attendee' field in new and edit form @@ -36,7 +38,7 @@ and this project adheres to * [Accompanying period work evaluations] list documents associated to a work by creation date, and then by id, from the most recent to older * [Course comment] add validationConstraint NotNull and NotBlank on comment content, to avoid sql error * [Notifications] delay the sending of notificaiton to kernel.terminate -* [Notifications / Period user change] fix the sending of notification when user changes +* [Notifications / Period user change] fix the sending of notification when user changes * [Activity form] invert 'incoming' and 'receiving' in Activity form * [Activity form] keep the same order for 'attendee' field in new and edit form * [list with period] use "sameas" test operator to introduce requestor in list From 48daed26f9501fb40f2f5112a994f75c34bf802f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 27 Apr 2022 14:30:50 +0200 Subject: [PATCH 15/23] replace BadRequestException by BadRequestHttpException --- .../CRUD/Controller/ApiController.php | 16 ++++++++-------- .../CRUD/Controller/CRUDController.php | 3 ++- .../Controller/SearchController.php | 3 +-- .../Controller/WorkflowController.php | 3 +-- .../AccompanyingCourseApiController.php | 10 +++++----- .../Controller/AccompanyingCourseController.php | 4 ++-- .../Controller/HouseholdController.php | 6 +++--- .../Controller/HouseholdMemberController.php | 4 ++-- .../Controller/SingleTaskController.php | 3 +-- 9 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php index a780af78a..9bf43b37e 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php @@ -16,9 +16,9 @@ use Chill\MainBundle\Serializer\Model\Collection; use Exception; use LogicException; use RuntimeException; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Serializer\Exception\NotEncodableValueException; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\SerializerInterface; @@ -55,7 +55,7 @@ class ApiController extends AbstractCRUDController return $this->entityDelete('_entity', $request, $id, $_format); default: - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This method is not implemented'); + throw new BadRequestHttpException('This method is not implemented'); } } @@ -120,7 +120,7 @@ class ApiController extends AbstractCRUDController return $this->entityPostAction('_entity', $request, $_format); default: - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This method is not implemented'); + throw new BadRequestHttpException('This method is not implemented'); } } @@ -160,7 +160,7 @@ class ApiController extends AbstractCRUDController try { $entity = $this->deserialize($action, $request, $_format, $entity); } catch (NotEncodableValueException $e) { - throw new BadRequestException('invalid json', 400, $e); + throw new BadRequestHttpException('invalid json', 400, $e); } $errors = $this->validate($action, $request, $_format, $entity); @@ -273,7 +273,7 @@ class ApiController extends AbstractCRUDController try { $postedData = $this->getSerializer()->deserialize($request->getContent(), $postedDataType, $_format, $postedDataContext); } catch (\Symfony\Component\Serializer\Exception\UnexpectedValueException $e) { - throw new BadRequestException(sprintf('Unable to deserialize posted ' . + throw new BadRequestHttpException(sprintf('Unable to deserialize posted ' . 'data: %s', $e->getMessage()), 0, $e); } @@ -290,7 +290,7 @@ class ApiController extends AbstractCRUDController break; default: - throw new BadRequestException('this method is not supported'); + throw new BadRequestHttpException('this method is not supported'); } $errors = $this->validate($action, $request, $_format, $entity, [$postedData]); @@ -408,7 +408,7 @@ class ApiController extends AbstractCRUDController return $this->json($entity, Response::HTTP_OK, [], $context); } - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This format is not implemented'); + throw new BadRequestHttpException('This format is not implemented'); } protected function entityPostAction($action, Request $request, string $_format): Response @@ -418,7 +418,7 @@ class ApiController extends AbstractCRUDController try { $entity = $this->deserialize($action, $request, $_format, $entity); } catch (NotEncodableValueException $e) { - throw new BadRequestException('invalid json', 400, $e); + throw new BadRequestHttpException('invalid json', 400, $e); } $errors = $this->validate($action, $request, $_format, $entity); diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php index 62d587ab3..edca07b41 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php @@ -25,6 +25,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Contracts\Translation\TranslatorInterface; @@ -1140,6 +1141,6 @@ class CRUDController extends AbstractController return $this->json($entity, Response::HTTP_OK, [], $context); } - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This format is not implemented'); + throw new BadRequestHttpException('This format is not implemented'); } } diff --git a/src/Bundle/ChillMainBundle/Controller/SearchController.php b/src/Bundle/ChillMainBundle/Controller/SearchController.php index 41349336a..496538665 100644 --- a/src/Bundle/ChillMainBundle/Controller/SearchController.php +++ b/src/Bundle/ChillMainBundle/Controller/SearchController.php @@ -22,7 +22,6 @@ use Chill\MainBundle\Search\UnknowSearchNameException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -216,7 +215,7 @@ class SearchController extends AbstractController $types = $request->query->get('type', []); if (count($types) === 0) { - throw new BadRequestException('The request must contains at ' + throw new BadRequestHttpException('The request must contains at ' . ' one type'); } diff --git a/src/Bundle/ChillMainBundle/Controller/WorkflowController.php b/src/Bundle/ChillMainBundle/Controller/WorkflowController.php index 103de6d84..2803ff254 100644 --- a/src/Bundle/ChillMainBundle/Controller/WorkflowController.php +++ b/src/Bundle/ChillMainBundle/Controller/WorkflowController.php @@ -25,7 +25,6 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -144,7 +143,7 @@ class WorkflowController extends AbstractController public function getAccessByAccessKey(EntityWorkflowStep $entityWorkflowStep, Request $request): Response { if (null === $accessKey = $request->query->get('accessKey', null)) { - throw new BadRequestException('accessKey is missing'); + throw new BadRequestHttpException('accessKey is missing'); } if (!$this->getUser() instanceof User) { diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index f1306640b..21db6b00c 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -33,10 +33,10 @@ use DateInterval; use DateTimeImmutable; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Serializer\Exception\RuntimeException; @@ -185,7 +185,7 @@ final class AccompanyingCourseApiController extends ApiController ->deserialize($request->getContent(), Person::class, $_format, []); if (null === $person) { - throw new BadRequestException('person id not found'); + throw new BadRequestHttpException('person id not found'); } // TODO add acl @@ -204,7 +204,7 @@ final class AccompanyingCourseApiController extends ApiController break; default: - throw new BadRequestException('This method is not supported'); + throw new BadRequestHttpException('This method is not supported'); } $errors = $this->validator->validate($accompanyingPeriod); @@ -247,12 +247,12 @@ final class AccompanyingCourseApiController extends ApiController } if (null === $requestor) { - throw new BadRequestException('Could not find any person or thirdparty', 0, null); + throw new BadRequestHttpException('Could not find any person or thirdparty', 0, null); } $accompanyingPeriod->setRequestor($requestor); } else { - throw new BadRequestException('method not supported'); + throw new BadRequestHttpException('method not supported'); } $errors = $this->validator->validate($accompanyingPeriod); diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php index b15f8adb9..4d78bb42b 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php @@ -21,9 +21,9 @@ use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Validator\ConstraintViolationInterface; @@ -255,7 +255,7 @@ class AccompanyingCourseController extends Controller $personIds = $request->query->get('person_id'); if (false === is_array($personIds)) { - throw new BadRequestException('person_id parameter should be an array'); + throw new BadRequestHttpException('person_id parameter should be an array'); } foreach ($personIds as $personId) { diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php index 7b6dc201e..503867a3e 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php @@ -21,8 +21,8 @@ use Chill\PersonBundle\Security\Authorization\HouseholdVoter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\FormInterface; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Security; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; @@ -202,7 +202,7 @@ class HouseholdController extends AbstractController $this->denyAccessUnlessGranted(HouseholdVoter::EDIT, $household); if (!$request->query->has('address_id')) { - throw new BadRequestException('parameter address_id is missing'); + throw new BadRequestHttpException('parameter address_id is missing'); } $address_id = $request->query->getInt('address_id'); @@ -218,7 +218,7 @@ class HouseholdController extends AbstractController } if (null === $address) { - throw new BadRequestException('The edited address does not belongs to the household'); + throw new BadRequestHttpException('The edited address does not belongs to the household'); } $form = $this->createForm(AddressDateType::class, $address, []); diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php index 2ec72a786..a595eb8c7 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php @@ -20,9 +20,9 @@ use Chill\PersonBundle\Form\HouseholdMemberType; use Chill\PersonBundle\Household\MembersEditor; use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Serializer\Exception; @@ -105,7 +105,7 @@ class HouseholdMemberController extends ApiController $ids = $request->query->get('persons', []); if (0 === count($ids)) { - throw new BadRequestException('parameters persons in query ' . + throw new BadRequestHttpException('parameters persons in query ' . 'is not an array or empty'); } diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index b4b6727b2..355015215 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -33,7 +33,6 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -494,7 +493,7 @@ final class SingleTaskController extends AbstractController ); default: - throw new BadRequestException("format not supported: {$_format}"); + throw new BadRequestHttpException("format not supported: {$_format}"); } } From 916e3ab02def2ae6e36963d36109eb6a66a91dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 27 Apr 2022 14:31:59 +0200 Subject: [PATCH 16/23] ignore phpcs cache for phpstan --- phpstan.neon.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index edec00554..3322f9539 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,6 +3,7 @@ parameters: paths: - src/ excludePaths: + - .php_cs* - docs/ - src/Bundle/*/Tests/* - src/Bundle/*/tests/* From 4794039250c3106d5fb3e8901e06ebe65aedb9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 27 Apr 2022 14:45:42 +0200 Subject: [PATCH 17/23] declare properties used for cache --- phpstan-critical.neon | 5 ----- src/Bundle/ChillPersonBundle/Entity/Person.php | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/phpstan-critical.neon b/phpstan-critical.neon index 262d3012f..1dc516834 100644 --- a/phpstan-critical.neon +++ b/phpstan-critical.neon @@ -5,11 +5,6 @@ parameters: count: 1 path: src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php - - - message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\Person\\:\\:\\$currentHouseholdParticipationAt\\.$#" - count: 3 - path: src/Bundle/ChillPersonBundle/Entity/Person.php - - message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\Household\\\\PersonHouseholdAddress\\:\\:\\$relation\\.$#" count: 1 diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index ef522f068..7f2630a1e 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -240,6 +240,11 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI */ private array $currentHouseholdAt = []; + /** + * Cache for the computation of current household participation. + */ + private array $currentHouseholdParticipationAt = []; + /** * The current person address. * From fa7850196f9a3d32b7878945ba92b3cb4f7a754e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 27 Apr 2022 14:46:08 +0200 Subject: [PATCH 18/23] force using strict type on comparison --- src/Bundle/ChillReportBundle/Controller/ReportController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillReportBundle/Controller/ReportController.php b/src/Bundle/ChillReportBundle/Controller/ReportController.php index bca915090..33ddd3a39 100644 --- a/src/Bundle/ChillReportBundle/Controller/ReportController.php +++ b/src/Bundle/ChillReportBundle/Controller/ReportController.php @@ -334,7 +334,7 @@ class ReportController extends AbstractController $cFGroupId = $request->query->get('cFGroup'); - if ($cFGroupId) { + if ($request->query->has('cFGroup')) { return $this->redirect( $this->generateUrl( 'report_new', @@ -391,7 +391,7 @@ class ReportController extends AbstractController { $cFGroupId = $request->query->get('cFGroup'); - if ($cFGroupId) { + if ($request->query->has('cFGroup')) { return $this->redirect( $this->generateUrl( 'report_export_list', From 9789c794025aa30e5b6e5001b53dfed6dd9406ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 27 Apr 2022 14:46:43 +0200 Subject: [PATCH 19/23] use strict type comparison and replace use of BadRequestException by BadRequestHttpException --- .../Controller/HouseholdMemberController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php index a595eb8c7..cacba0630 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php @@ -121,7 +121,8 @@ class HouseholdMemberController extends ApiController } } - if ($householdId = $request->query->get('household', false)) { + if ($request->query->has('household')) { + $householdId = $request->query->get('household', false); $household = $em->getRepository(Household::class) ->find($householdId); $allowHouseholdCreate = false; @@ -189,7 +190,7 @@ class HouseholdMemberController extends ApiController ['groups' => ['read']] ); } catch (Exception\InvalidArgumentException|Exception\UnexpectedValueException $e) { - throw new BadRequestException("Deserialization error: {$e->getMessage()}", 45896, $e); + throw new BadRequestHttpException("Deserialization error: {$e->getMessage()}", 45896, $e); } // TODO ACL From 9244040d7b5f462ab7e9d31d9bc8b27e4e284d57 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 27 Apr 2022 14:51:37 +0200 Subject: [PATCH 20/23] csfixes --- src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php | 1 - .../Security/Authorization/AccompanyingPeriodCommentVoter.php | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 20156e4c4..8495afa89 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -1258,7 +1258,6 @@ class AccompanyingPeriod implements */ public function setPinnedComment(?Comment $comment = null): self { - if (null !== $this->pinnedComment) { $this->addComment($this->pinnedComment); } diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php index 64fdbb796..6e326b990 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodCommentVoter.php @@ -41,8 +41,10 @@ class AccompanyingPeriodCommentVoter extends Voter switch ($attribute) { case self::EDIT: return $this->security->isGranted(AccompanyingPeriodVoter::EDIT, $subject->getAccompanyingPeriod()); + case self::DELETE: return $this->security->isGranted(AccompanyingPeriodVoter::EDIT, $subject->getAccompanyingPeriod()); + default: throw new UnexpectedValueException("This attribute {$attribute} is not supported"); } From ed35822eb5ec200050bc43f846c0eda95f522703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 29 Apr 2022 14:10:41 +0200 Subject: [PATCH 21/23] changelog: release --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d25aa9a8..3c041f9cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,13 +11,17 @@ and this project adheres to ## Unreleased + +## Test releases + +### 2021-04-28 + * [address] fix bug when editing address: update location and addressreferenceId + better update of the map in edition (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/593) * [main] avoid address reference search on undefined post code (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/561) * [person] prevent duplicate relationship in filiation/household graph (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/560) * [Documents] Validate storedObject and allow for null data (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/565) * [parcours]: Comments can be unpinned + edit/delete for all users that are allowed to edit parcours (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/566) -## Test releases ### 2021-04-26 From 1e06926f6d0d77d7ebce5e9448ee0592554f63dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 29 Apr 2022 14:11:32 +0200 Subject: [PATCH 22/23] Load relationships without gender in french fixtures --- CHANGELOG.md | 1 + .../DataFixtures/ORM/LoadRelations.php | 24 ++++++------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c041f9cf..61c429e57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to ## Unreleased +* Load relationships without gender in french fixtures ## Test releases diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php index e2bb469bc..c7ce18091 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php @@ -21,23 +21,13 @@ class LoadRelations extends Fixture implements FixtureGroupInterface public const RELATION_KEY = 'relations'; public const RELATIONS = [ - ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fille']], - ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fils']], - ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fille']], - ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fils']], - - ['title' => ['fr' => 'Frère'], 'reverseTitle' => ['fr' => 'Frère']], - ['title' => ['fr' => 'Soeur'], 'reverseTitle' => ['fr' => 'Soeur']], - ['title' => ['fr' => 'Frère'], 'reverseTitle' => ['fr' => 'Soeur']], - - ['title' => ['fr' => 'Demi-frère'], 'reverseTitle' => ['fr' => 'Demi-frère']], - ['title' => ['fr' => 'Demi-soeur'], 'reverseTitle' => ['fr' => 'Demi-soeur']], - ['title' => ['fr' => 'Demi-frère'], 'reverseTitle' => ['fr' => 'Demi-soeur']], - - ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Neveu']], - ['title' => ['fr' => 'Oncle'], 'reverseTitle' => ['fr' => 'Nièce']], - ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Neveu']], - ['title' => ['fr' => 'Tante'], 'reverseTitle' => ['fr' => 'Nièce']], + ['title' => ['fr' => 'Parent'], 'reverseTitle' => ['fr' => 'Enfant']], + ['title' => ['fr' => 'En couple'], 'reverseTitle' => ['fr' => 'En couple']], + ['title' => ['fr' => 'Beau parent'], 'reverseTitle' => ['fr' => 'Belle-fille·beau-fils']], + ['title' => ['fr' => 'Frère·Sœur'], 'reverseTitle' => ['fr' => 'Frère·Sœur']], + ['title' => ['fr' => 'Demi-frère·sœur'], 'reverseTitle' => ['fr' => 'Demi-frère·sœur']], + ['title' => ['fr' => 'Grand-parent'], 'reverseTitle' => ['fr' => 'Petit-enfant']], + ['title' => ['fr' => 'Oncle·Tante'], 'reverseTitle' => ['fr' => 'Neveu·Nièce']], ]; public static function getGroups(): array From 770010ceb83abe3918dfc1b5a1b6830199b5fd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 29 Apr 2022 15:51:54 +0200 Subject: [PATCH 23/23] Add command to remove old draft accompanying periods --- CHANGELOG.md | 1 + ...emoveOldDraftAccompanyingPeriodCommand.php | 64 +++++++++++ .../OldDraftAccompanyingPeriodRemover.php | 103 ++++++++++++++++++ ...raftAccompanyingPeriodRemoverInterface.php | 19 ++++ .../migrations/Version20220429133023.php | 39 +++++++ 5 files changed, 226 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Command/RemoveOldDraftAccompanyingPeriodCommand.php create mode 100644 src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemover.php create mode 100644 src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemoverInterface.php create mode 100644 src/Bundle/ChillPersonBundle/migrations/Version20220429133023.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 61c429e57..a985c8493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to * Load relationships without gender in french fixtures +* Add command to remove old draft accompanying periods ## Test releases diff --git a/src/Bundle/ChillPersonBundle/Command/RemoveOldDraftAccompanyingPeriodCommand.php b/src/Bundle/ChillPersonBundle/Command/RemoveOldDraftAccompanyingPeriodCommand.php new file mode 100644 index 000000000..5d503007f --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Command/RemoveOldDraftAccompanyingPeriodCommand.php @@ -0,0 +1,64 @@ +logger = $logger; + $this->remover = $remover; + } + + protected function configure(): void + { + $this + ->setDescription('Remove draft accompanying period which are still draft and unused') + ->addArgument('interval', InputArgument::OPTIONAL, 'The interval for unactive periods', 'P15D'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->info('[' . $this->getName() . '] started', [ + 'interval' => $input->getArgument('interval'), + ]); + + try { + $interval = new DateInterval($input->getArgument('interval')); + } catch (Exception $e) { + $this->logger->error('[' . $this->getName() . '] bad interval'); + + throw $e; + } + + $this->remover->remove($interval); + + $this->logger->info('[' . $this->getName() . '] end of command'); + + return 0; + } +} diff --git a/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemover.php b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemover.php new file mode 100644 index 000000000..47a34e88c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemover.php @@ -0,0 +1,103 @@ +em = $em; + $this->logger = $logger; + } + + public function remove(DateInterval $interval): void + { + $this->logger->debug('[' . __CLASS__ . '] start to remove old periods', [ + 'interval' => $interval->format('%d days'), + ]); + + $beforeDate = (new DateTimeImmutable('now'))->sub($interval); + + $results = $this->em->wrapInTransaction(static function (EntityManagerInterface $em) use ($beforeDate) { + $subDQL = 'SELECT p FROM ' . AccompanyingPeriod::class . ' p WHERE p.createdAt < :beforeDate AND p.step = :draft'; + $parameters = [ + 'beforeDate' => $beforeDate, + 'draft' => AccompanyingPeriod::STEP_DRAFT, + ]; + + $resources = $em->createQuery( + 'DELETE ' . AccompanyingPeriod\Resource::class . " r WHERE r.accompanyingPeriod IN ({$subDQL})" + ) + ->setParameters($parameters) + ->getSingleScalarResult(); + + $participations = $em->createQuery( + 'DELETE ' . AccompanyingPeriodParticipation::class . " part WHERE part.accompanyingPeriod IN ({$subDQL})" + ) + ->setParameters($parameters) + ->getSingleScalarResult(); + + $userHistory = $em->createQuery( + 'DELETE ' . AccompanyingPeriod\UserHistory::class . " h WHERE h.accompanyingPeriod IN ({$subDQL})" + ) + ->setParameters($parameters) + ->getSingleScalarResult(); + + $comments = $em->createQuery( + 'DELETE ' . AccompanyingPeriod\Comment::class . " c WHERE c.accompanyingPeriod IN ({$subDQL})" + ) + ->setParameters($parameters) + ->getSingleScalarResult(); + + $documents = $em->createQuery( + 'DELETE ' . AccompanyingCourseDocument::class . " d WHERE d.course IN ({$subDQL})" + ) + ->setParameters($parameters) + ->getSingleScalarResult(); + + $periods = $em + ->createQuery( + 'DELETE ' . AccompanyingPeriod::class . ' p WHERE p.createdAt < :beforeDate + AND p.step = :draft' + ) + ->setParameter(':beforeDate', $beforeDate, Types::DATETIME_IMMUTABLE) + ->setParameter(':draft', AccompanyingPeriod::STEP_DRAFT) + ->getSingleScalarResult(); + + return [ + 'comments' => $comments, + 'documents' => $documents, + 'participations' => $participations, + 'periods' => $periods, + 'resources' => $resources, + 'userHistory' => $userHistory, + ]; + }); + + $this->logger->info('[' . __CLASS__ . '] periods removed', array_merge($results, [ + 'interval' => $interval->format('%d days'), + ])); + } +} diff --git a/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemoverInterface.php b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemoverInterface.php new file mode 100644 index 000000000..882fefe3b --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriod/OldDraftAccompanyingPeriodRemoverInterface.php @@ -0,0 +1,19 @@ +addSql('ALTER TABLE "accompanying_periods_scopes" + DROP CONSTRAINT "fk_87c4eab032a7a428", + ADD CONSTRAINT "fk_87c4eab032a7a428" FOREIGN KEY (accompanying_period_id) REFERENCES chill_person_accompanying_period(id) + '); + } + + public function getDescription(): string + { + return 'apply CASCADE DELETE on entity related to accompanying periods'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE "accompanying_periods_scopes" + DROP CONSTRAINT "fk_87c4eab032a7a428", + ADD CONSTRAINT "fk_87c4eab032a7a428" FOREIGN KEY (accompanying_period_id) REFERENCES chill_person_accompanying_period(id) ON DELETE CASCADE + '); + } +}