diff --git a/assets/controllers/form_signalement_front.js b/assets/controllers/form_signalement_front.js index b856df05..969bf325 100644 --- a/assets/controllers/form_signalement_front.js +++ b/assets/controllers/form_signalement_front.js @@ -849,9 +849,9 @@ class PunaisesFrontSignalementController { self.refreshStep(nbStep); }, error: function (xhr, desc, err) { - console.log(xhr); if (xhr.responseJSON != undefined) { - alert("Erreur lors de l'ajout du signalement (" + xhr.responseJSON.errors[0].message + ")"); + const errorValues = Object.values(xhr.responseJSON.errors); + alert("Erreur lors de l'ajout du signalement (" + errorValues[0].errors[0] + ")"); } else { alert("Erreur lors de l'ajout du signalement"); } diff --git a/src/Controller/Front/SignalementController.php b/src/Controller/Front/SignalementController.php index 35dd300a..483da392 100644 --- a/src/Controller/Front/SignalementController.php +++ b/src/Controller/Front/SignalementController.php @@ -11,6 +11,7 @@ use App\Manager\SignalementManager; use App\Repository\EntrepriseRepository; use App\Repository\TerritoireRepository; +use App\Service\FormHelper; use App\Service\Mailer\MailerProvider; use App\Service\Signalement\GeolocateService; use App\Service\Signalement\ReferenceGenerator; @@ -65,11 +66,10 @@ public function save( GeolocateService $geolocateService, ): Response { $signalement = new Signalement(); - $form = $this->createForm(SignalementFrontType::class, $signalement, ['validation_groups' => 'front_add_signalement_logement']); + $form = $this->createForm(SignalementFrontType::class, $signalement); $form->handleRequest($request); - $submittedToken = $request->request->get('_csrf_token'); - if ($form->isValid() && $this->isCsrfTokenValid('front-add-signalement', $submittedToken)) { + if ($form->isValid()) { $signalement ->setType(SignalementType::TYPE_LOGEMENT) ->setReference($referenceGenerator->generate()) @@ -79,19 +79,15 @@ public function save( $filesPosted = $request->files->get('file-upload'); $filesToSave = $uploadHandlerService->handleUploadFilesRequest($filesPosted); $signalement->setPhotos($filesToSave); + $geolocateService->geolocate($signalement); - if ([] === $signalement->getGeoloc()) { - $geolocateService->geolocate($signalement); - } - if (null !== $signalement->getCodePostal()) { - $zipCode = $zipCodeService->getByCodePostal($signalement->getCodePostal()); - $territoire = $territoireRepository->findOneBy(['zip' => $zipCode]); - $signalement->setTerritoire($territoire); - - $signalementManager->save($signalement); - } else { - return $this->json(['response' => 'error', 'errors' => 'code postal null'], Response::HTTP_BAD_REQUEST); + $zipCode = $zipCodeService->getByCodePostal($signalement->getCodePostal()); + $territoire = $territoireRepository->findOneBy(['zip' => $zipCode]); + if (!$territoire) { + return $this->json(['response' => 'error', 'errors' => 'territoire introuvable sur le code postal '.$signalement->getCodePostal()], Response::HTTP_BAD_REQUEST); } + $signalement->setTerritoire($territoire); + $signalementManager->save($signalement); if ($signalement->isAutotraitement()) { if ($signalement->getTerritoire()->isActive()) { @@ -123,7 +119,8 @@ public function save( return $this->json(['response' => 'success']); } + $errors = FormHelper::getErrorsFromForm($form); - return $this->json(['response' => 'error', 'errors' => $form->getErrors(true)], Response::HTTP_BAD_REQUEST); + return $this->json(['response' => 'error', 'errors' => $errors], Response::HTTP_BAD_REQUEST); } } diff --git a/src/Entity/Signalement.php b/src/Entity/Signalement.php index 7c26615a..484cf907 100644 --- a/src/Entity/Signalement.php +++ b/src/Entity/Signalement.php @@ -32,12 +32,30 @@ class Signalement private ?string $uuid = null; #[ORM\Column(length: 255, nullable: true)] + #[Assert\Length(max: 255)] + #[Assert\NotBlank( + message: 'Veuillez renseigner une adresse.', + groups: ['front_add_signalement_logement'] + )] private ?string $adresse = null; #[ORM\Column(length: 10)] + #[Assert\NotBlank( + message: 'Veuillez renseigner le code postal.', + groups: ['front_add_signalement_logement'] + )] + #[Assert\Regex( + pattern: '/^[0-9]{5}$/', + message: 'Veuillez utiliser un code postal valide', + )] private ?string $codePostal = null; #[ORM\Column(length: 255, nullable: true)] + #[Assert\Length(max: 255)] + #[Assert\NotBlank( + message: 'Veuillez renseigner la ville.', + groups: ['front_add_signalement_logement'] + )] private ?string $ville = null; #[ORM\Column(length: 20, nullable: true)] @@ -47,6 +65,7 @@ class Signalement private ?bool $construitAvant1948 = null; #[ORM\Column(length: 50, nullable: true)] + #[Assert\Length(max: 50)] #[Assert\NotBlank( message: 'Veuillez renseigner votre nom.', groups: ['front_add_signalement_logement', 'back_add_signalement_logement'] @@ -54,6 +73,7 @@ class Signalement private ?string $nomOccupant = null; #[ORM\Column(length: 50, nullable: true)] + #[Assert\Length(max: 50)] #[Assert\NotBlank( message: 'Veuillez renseigner votre prenom.', groups: ['front_add_signalement_logement', 'back_add_signalement_logement'] @@ -66,11 +86,20 @@ class Signalement match: true, message: 'Merci de saisir le numéro de téléphone au bon format' )] + #[Assert\NotBlank( + message: 'Veuillez renseigner votre numéro de téléphone.', + groups: ['front_add_signalement_logement'] + )] private ?string $telephoneOccupant = null; #[ORM\Column(length: 100, nullable: true)] + #[Assert\Length(max: 100)] #[Assert\Email] - #[Assert\NotBlank(message: 'Veuillez renseigner votre email.', groups: ['front_add_signalement_logement'])] + #[Assert\NotBlank(message: 'Veuillez renseigner votre e-mail.', groups: ['front_add_signalement_logement'])] + #[Assert\Email( + message: 'Veuillez renseigner une adresse e-mail valide.', + groups: ['front_add_signalement_logement'] + )] private ?string $emailOccupant = null; #[ORM\Column(length: 30, nullable: true)] @@ -80,6 +109,16 @@ class Signalement private ?\DateTimeInterface $dateIntervention = null; #[ORM\Column(type: Types::SMALLINT, nullable: true)] + #[Assert\Range( + min: 0, + max: 4, + notInRangeMessage: 'Le niveau d\'infestation doit être compris entre 1 et 4.', + groups: ['front_add_signalement_logement'] + )] + #[Assert\NotBlank( + message: 'Veuillez renseigner un niveau d\'infestation.', + groups: ['front_add_signalement_logement'] + )] private ?int $niveauInfestation = null; #[ORM\Column(type: Types::JSON, nullable: true)] @@ -113,6 +152,7 @@ class Signalement private ?string $localisationDansImmeuble = null; #[ORM\Column(length: 10, nullable: true)] + #[Assert\Regex(pattern: '/^[0-9][0-9A-Za-z][0-9]{3}$/', message: 'Le code insee doit être composé de 5 caractères.')] private ?string $codeInsee = null; #[ORM\ManyToOne(inversedBy: 'signalements')] @@ -128,6 +168,14 @@ class Signalement private ?bool $autotraitement = null; #[ORM\Column(type: Types::SMALLINT, nullable: true)] + #[Assert\NotBlank( + message: 'Veuillez renseigner une superficie.', + groups: ['front_add_signalement_logement'] + )] + #[Assert\Regex( + pattern: '/^[0-9]{1,5}$/', + message: 'Veuillez renseigner une superficie valide', + )] private ?int $superficie = null; #[ORM\Column(length: 20, nullable: true)] @@ -164,6 +212,7 @@ class Signalement private ?bool $locataire = null; #[ORM\Column(length: 100, nullable: true)] + #[Assert\Length(max: 100)] private ?string $nomProprietaire = null; #[ORM\Column(nullable: true)] @@ -173,6 +222,7 @@ class Signalement private ?bool $allocataire = null; #[ORM\Column(length: 50, nullable: true)] + #[Assert\Length(max: 50)] private ?string $numeroAllocataire = null; #[ORM\Column(nullable: true)] diff --git a/src/Form/SignalementFrontType.php b/src/Form/SignalementFrontType.php index 069fd605..162ad1e1 100644 --- a/src/Form/SignalementFrontType.php +++ b/src/Form/SignalementFrontType.php @@ -4,7 +4,6 @@ use App\Entity\Signalement; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; @@ -15,8 +14,6 @@ use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Validator\Constraints\Email; class SignalementFrontType extends AbstractType { @@ -56,10 +53,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ], 'label' => 'La superficie de mon logement est de…', 'required' => true, - 'constraints' => [ - new Assert\NotBlank(message: 'Veuillez renseigner une superficie'), - new Assert\Regex('/[0-9]{5}/', 'Veuillez renseigner une superficie valide'), - ], ]) ->add('adresse', TextType::class, [ 'attr' => [ @@ -89,10 +82,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'class' => 'fr-hint-text', ], 'required' => true, - 'constraints' => [ - new Assert\NotBlank(message: 'Veuillez renseigner le code postal'), - new Assert\Regex('/[0-9]{5}/', 'Veuillez utiliser un code postal valide'), - ], ]) ->add('codeInsee', HiddenType::class, [ 'attr' => [ @@ -117,8 +106,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'class' => 'fr-hidden', ], 'required' => false, + 'mapped' => false, ]) - // Step info_locataire ->add('locataire', ChoiceType::class, [ 'attr' => [ @@ -323,9 +312,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'class' => 'fr-hint-text', ], 'required' => false, - 'constraints' => [ - new Assert\Regex('/[0-9]{10}/', 'Veuillez renseigner un numéro de téléphone valide'), - ], ]) ->add('emailOccupant', EmailType::class, [ 'attr' => [ @@ -342,12 +328,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'class' => 'fr-hint-text', ], 'required' => false, - 'constraints' => [ - new Email( - mode: Email::VALIDATION_MODE_STRICT, - message: 'Veuillez renseigner un email valide.' - ), - ], ]) ->add('autotraitement', HiddenType::class, [ 'attr' => [ @@ -356,27 +336,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'empty_data' => false, ]) ; - $builder->get('geoloc')->addModelTransformer(new CallbackTransformer( - function ($tagsAsArray) { - // transform the array to a string - if (!empty($tagsAsArray)) { - return $tagsAsArray[0].'|'.$tagsAsArray[1]; - } - - return ''; - }, - function ($tagsAsString) { - // transform the string back to an array - if (!empty($tagsAsString)) { - $coord = explode('|', $tagsAsString); - - return ['lat' => $coord[0], 'lng' => $coord[1]]; - } - - return []; - } - )); - $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) { /** @var Signalement $signalement */ $signalement = $event->getData(); @@ -404,8 +363,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'data_class' => Signalement::class, 'allow_extra_fields' => true, - 'csrf_protection' => false, 'validation_groups' => ['Default', 'front_add_signalement_logement'], + 'csrf_token_id' => 'signalement_front', ]); } diff --git a/src/Service/FormHelper.php b/src/Service/FormHelper.php new file mode 100644 index 00000000..d55d8f4e --- /dev/null +++ b/src/Service/FormHelper.php @@ -0,0 +1,31 @@ +getErrors() as $error) { + if ($recursive) { + $errors[] = $error->getMessage(); + } else { + $errors['__nopath__']['errors'][] = $error->getMessage(); + } + } + foreach ($form->all() as $childForm) { + if ($childForm instanceof FormInterface) { + if ($childErrors = self::getErrorsFromForm($childForm, true)) { + foreach ($childErrors as $childError) { + $errors[$childForm->getName()]['errors'][] = $childError; + } + } + } + } + + return $errors; + } +} diff --git a/templates/front_signalement/_partial_step_info_logement.html.twig b/templates/front_signalement/_partial_step_info_logement.html.twig index b494fac9..164eaf54 100644 --- a/templates/front_signalement/_partial_step_info_logement.html.twig +++ b/templates/front_signalement/_partial_step_info_logement.html.twig @@ -14,7 +14,7 @@ Étape suivante : Durée de l'infestation

- + {{ form_widget(form._token) }} {{ forms.radio_choice(form.typeLogement, 'Veuillez renseigner le type de logement.') }}
diff --git a/templates/front_signalement/_partial_step_info_usager.html.twig b/templates/front_signalement/_partial_step_info_usager.html.twig index 273954b0..9e11b84c 100644 --- a/templates/front_signalement/_partial_step_info_usager.html.twig +++ b/templates/front_signalement/_partial_step_info_usager.html.twig @@ -80,8 +80,6 @@ {{ form_widget(form.autotraitement) }} - -
{% include 'front_signalement/_partial_signalement_navigation_container.html.twig' with {'next': 'Recevoir le protocole', 'previous': 'Retour' } %}
diff --git a/tests/Functional/Controller/Front/SignalementControllerTest.php b/tests/Functional/Controller/Front/SignalementControllerTest.php index b42d39fe..2fdd5062 100644 --- a/tests/Functional/Controller/Front/SignalementControllerTest.php +++ b/tests/Functional/Controller/Front/SignalementControllerTest.php @@ -23,9 +23,10 @@ protected function setUp(): void /** @dataProvider providePayloadSignalement */ public function testAddSignalementLogement(array $payload, ?string $codePostal = null): void { + $csrf_token = $this->generateCsrfToken($this->client, 'signalement_front'); + $payload['_token'] = $csrf_token; $payloadSignalement = [ 'signalement_front' => $payload, - '_csrf_token' => $this->generateCsrfToken($this->client, 'front-add-signalement'), 'code-postal' => $codePostal, ]; @@ -36,6 +37,7 @@ public function testAddSignalementLogement(array $payload, ?string $codePostal = $this->assertEquals(Response::HTTP_OK, $this->client->getResponse()->getStatusCode()); $bodyContent = $this->client->getResponse()->getContent(); + $this->assertStringContainsString('{"response":"success"}', $bodyContent); $this->assertEquals(json_decode($bodyContent, true)['response'], 'success'); } @@ -43,19 +45,19 @@ public function providePayloadSignalement(): \Generator { yield 'Post signalement in territory not open' => [ [ - 'superficie' => '', - 'adresse' => '', + 'superficie' => '45', + 'adresse' => '8 chemin de la route', 'codePostal' => '18250', 'codeInsee' => '', - 'ville' => '', + 'ville' => 'Achères', 'geoloc' => '', 'nomProprietaire' => '', 'numeroAllocataire' => '', 'infestationLogementsVoisins' => '2', - 'niveauInfestation' => '', + 'niveauInfestation' => '0', 'nomOccupant' => 'Doe', 'prenomOccupant' => 'John', - 'telephoneOccupant' => '', + 'telephoneOccupant' => '0607060706', 'emailOccupant' => 'john.doe@punaises.com', 'autotraitement' => 'true', ],