diff --git a/webapp/src/Form/User/SignupFormType.php b/webapp/src/Form/User/SignupFormType.php new file mode 100644 index 0000000000000000000000000000000000000000..624f376f86d47408453518fccf4b277f22259dbc --- /dev/null +++ b/webapp/src/Form/User/SignupFormType.php @@ -0,0 +1,130 @@ +<?php + +/* + * This file is part of the Comptoir-du-Libre software. + * <https://gitlab.adullact.net/Comptoir/comptoir-du-libre> + * + * Copyright (c) ADULLACT <https://adullact.org> + * Association des Développeurs et Utilisateurs de Logiciels Libres + * pour les Administrations et les Collectivités Territoriales + * + * Comptoir-du-Libre 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. + * + * You should have received a copy of the GNU Affero General Public License + * along with this software. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>. + */ + +declare(strict_types=1); + +namespace App\Form\User; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\EmailType; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Form\Extension\Core\Type\RepeatedType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Translation\TranslatableMessage; +use Symfony\Component\Validator\Constraints\Length; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\Email; + +class SignupFormType extends AbstractType +{ + public const HONEYPOT_FIELD_NAME = 'email'; + public const EMAIL_FIELD_NAME = 'login'; + + public function buildForm(FormBuilderInterface $builder, array $options): void + { + + $builder + ->add(self::HONEYPOT_FIELD_NAME, EmailType::class, [ + 'label' => 'signup.form.label.email', + 'required' => false, + 'label_attr' => [ + 'tabindex' => "-1", + 'aria-hidden' => "true", + 'class' => 'visually-hidden' + ], + 'attr' => [ + 'tabindex' => "-1", + 'aria-hidden' => "true", + 'type' => 'email', + 'class' => 'visually-hidden' + ], + ]) + ->add(self::EMAIL_FIELD_NAME, EmailType::class, [ + + 'label' => 'signup.form.label.email', + 'help' => 'signup.form.label.email.help', + 'constraints' => [ + new NotBlank([ + 'message' => 'common.validator.help.field.error.required', + ]), + new Email([ + 'mode' => 'html5', + 'message' => 'common.validator.help.email.error.not-valid', + ]), + ], + ]) + ->add('plainPassword', RepeatedType::class, [ + 'type' => PasswordType::class, + 'options' => [ + 'attr' => [ + 'autocomplete' => 'new-password', + 'minlength' => $options['min_password_length'], + 'maxlength' => 4096, // max length allowed by Symfony for security reasons + ], + ], + 'first_options' => [ + 'constraints' => [ + new NotBlank([ + 'message' => 'common.validator.help.field.error.required', + ]), + new Length([ + 'min' => $options['min_password_length'], +// 'minMessage' => 'Password should be at least {{ limit }} characters', + 'minMessage' => new TranslatableMessage( + message: 'common.validator.help.password.error.too-short', + ), + 'max' => 4096, // max length allowed by Symfony for security reasons + ]), + ], + 'label' => 'signup.form.label.password', + 'help_html' => true, + 'help' => new TranslatableMessage( + message: 'signup.form.label.password.help', + parameters: ['{ min_password_length }' => $options['min_password_length']], + domain: 'messages' + ), + ], + 'second_options' => [ + 'label' => 'signup.form.label.password-repeat', + 'help' => 'signup.form.label.password-repeat.help', + ], + 'invalid_message' => 'common.validator.help.password.error.password-must-match', + // Instead of being set onto the object directly, + // this is read and encoded in the controller + 'mapped' => false, + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'min_password_length' => 16, + // enable/disable CSRF protection for this form + 'csrf_protection' => true, + // the name of the hidden HTML field that stores the token + 'csrf_field_name' => 'csrf_token_Signup', + // an arbitrary string used to generate the value of the token + // using a different string for each form improves its security + 'csrf_token_id' => 'task_SignupFormType', + ]); + $resolver->setAllowedTypes('min_password_length', 'int'); + } +} diff --git a/webapp/templates/app_base_header.html.twig b/webapp/templates/app_base_header.html.twig index 48e17137bd68560a110d0160a99d62be470252b0..a4aab1ceeed6a4654f51f589407fdc6a3dbcbf19 100644 --- a/webapp/templates/app_base_header.html.twig +++ b/webapp/templates/app_base_header.html.twig @@ -40,7 +40,9 @@ </li> {% else %} <li class="d-flex align-items-start mb-1"> - {{ 'public.link.signup'|trans }} + <a href="{{ path('app_account_signup_init') }}"> + {{ 'public.link.signup'|trans }} + </a> </li> <li class="d-flex align-items-start mb-1"> <a href="{{ path('app_account_login') }}"> diff --git a/webapp/templates/user/signup.html.twig b/webapp/templates/user/signup.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..06b1168ca37c67d55987928f7656e1cf143ef059 --- /dev/null +++ b/webapp/templates/user/signup.html.twig @@ -0,0 +1,46 @@ +{% extends 'app_base.html.twig' %} +{% form_theme signupForm 'bootstrap_5_layout.html.twig' %} + +{% block title %} {{ 'signup.head.title'|trans }} - {{ app_name }}{% endblock %} +{% block body %} + <nav aria-label="breadcrumb"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"> + <a href="{{ path('app_home_i18n') }}">{{ 'breadcrumb.homepage'|trans }}</a> + </li> + <li class="breadcrumb-item active"> + <a href="{{ path('app_account_signup_init') }}" + aria-current="page">{{ 'breadcrumb.user.signup'|trans }}</a> + </li> + </ol> + </nav> + + <h1> + {{ 'signup.page.title'|trans }} + </h1> + <div class="col-md-8"> +{# {{ form_start(signupForm) }} #} +{# {{ form_start(signupForm, {'attr': {'novalidate': 'novalidate'}}) }} #} + {{ form_start(signupForm) }} + {{ form_row(signupForm.email) }} + <fieldset class="mt-4 mb-4 "> + <legend class="text-xl text-bg-dark px-2"> + {{ 'signup.form.fieldset.user.title'|trans }} + </legend> + {{ form_row(signupForm.login) }} + </fieldset> + + <fieldset class="mt-4 mb-4 "> + <legend class="text-xl text-bg-dark px-2"> + {{ 'signup.form.fieldset.password.title'|trans }} + </legend> + {{ form_row(signupForm.plainPassword) }} + </fieldset> + + <button id="public_signupForm_submit" class="btn btn-primary"> + {{ 'signup.form.submit'|trans|raw }} + </button> + {{ form_end(signupForm) }} + </div> + +{% endblock %} diff --git a/webapp/translations/messages+intl-icu.en.yaml b/webapp/translations/messages+intl-icu.en.yaml index 4e9a2ee61596b1c9499cc04438a5d1977616f282..0861241f9e3a0b6c64b38c81bca641dbaee5e107 100644 --- a/webapp/translations/messages+intl-icu.en.yaml +++ b/webapp/translations/messages+intl-icu.en.yaml @@ -28,6 +28,7 @@ user.link.profile: 'Profile' ################################################################################################################## breadcrumb.homepage: 'Home' breadcrumb.user.login: 'Sign in' +breadcrumb.user.signup: 'Sign up' breadcrumb.user.lost_password.form: 'Reset your password' ################################################################################################################## breadcrumb.user.account: 'Account setting' @@ -68,6 +69,22 @@ login.form.label.account: 'Email' login.form.label.password: 'Password' login.form.submit: '<strong>Sign in</strong> to your account' ################################################################################################################## +signup.head.title: 'Create an account' +signup.page.title: 'Create your account' +signup.form.submit: '<strong>Create</strong> your account' +signup.form.fieldset.user.title: 'User account' +signup.form.label.email: 'Email address' +signup.form.label.email.help: 'Enter your email address, and we will send you a link to activate your account.' +signup.form.fieldset.password.title: 'Password' +signup.form.label.password: 'Your password' +signup.form.label.password.help: | + Please enter your password. + It should be at least <strong>{ min_password_length }</strong> characters. +signup.form.label.password-repeat: 'Repeat password' +signup.form.label.password-repeat.help: 'Please repeat your password.' +signup.success: 'Your account has been successfully created.' +signup.error.account_already_exists: 'User account already exists' +################################################################################################################## forgot_password.request.head.title: 'Forgot your password?' forgot_password.request.page.title: 'Forgot your password?' forgot_password.request.form.submit: 'Send password reset email' diff --git a/webapp/translations/messages+intl-icu.fr.yaml b/webapp/translations/messages+intl-icu.fr.yaml index a0762a4c112883911f2cee6ec1371415139d616d..bb36f9662da97307990d65d7b9009756411b8013 100644 --- a/webapp/translations/messages+intl-icu.fr.yaml +++ b/webapp/translations/messages+intl-icu.fr.yaml @@ -29,6 +29,7 @@ user.link.profile: 'Profil' ################################################################################################################## breadcrumb.homepage: 'Accueil' breadcrumb.user.login: 'Se connecter' +breadcrumb.user.signup: 'Créer un compte' breadcrumb.user.lost_password.form: 'Réinitialiser votre mot de passe' ################################################################################################################## breadcrumb.user.account: 'Paramètres' @@ -69,6 +70,23 @@ login.form.label.account: 'Adresse email' login.form.label.password: 'Mot de passe' login.form.submit: '<strong>Se connecter</strong> à votre compte' ################################################################################################################## +signup.head.title: 'Créer un compte' +signup.page.title: 'Créer un compte' +signup.form.submit: '<strong>Créer</strong> votre compte' +signup.form.fieldset.user.title: 'Votre compte utilisateur' +signup.form.label.email: 'Adresse email' +signup.form.label.email.help: 'Saisir votre adresse email et nous vous enverrons un lien pour activer votre compte.' +signup.form.fieldset.password.title: 'Votre mot de passe' +signup.form.label.password: 'Mot de passe' +signup.form.label.password.help: | + Veuillez saisir votre mot de passe. + Il doit comporter au moins <strong>{ min_password_length }</strong> caractères. +signup.form.label.password-repeat: 'Répéter le mot de passe' +signup.form.label.password-repeat.help: 'Veuillez de nouveau saisir votre mot de passe' +signup.success: 'Votre compte a été créé avec succès.' +signup.error.account_already_exists: "Un compte utilisateur existe déjà pour cette adresse mail." + # Un utilisateur ayant ce courriel existe déjà . +################################################################################################################## forgot_password.request.head.title: 'Mot de passe oublié ?' forgot_password.request.page.title: 'Mot de passe oublié ?' forgot_password.request.form.submit: 'Réinitialiser votre <strong>mot</strong> de <strong>passe</strong>' diff --git a/webapp/translations/validators+intl-icu.en.yaml b/webapp/translations/validators+intl-icu.en.yaml index 0bf477eeb4e87e988ede3a68e20c93a2f7c74b3e..6d2720ee5274d9747cad44d9c41ad2dbcbb0ce83 100644 --- a/webapp/translations/validators+intl-icu.en.yaml +++ b/webapp/translations/validators+intl-icu.en.yaml @@ -1,3 +1,4 @@ +common.validator.help.password.error.password-must-match: 'The password fields must match.' common.validator.help.password.error.new-password-must-match: 'The new password fields must match.' common.validator.help.email.error.not-valid: 'Please enter a valid email address.' common.validator.help.password.error.too-short: 'Password size is too small.' diff --git a/webapp/translations/validators+intl-icu.fr.yaml b/webapp/translations/validators+intl-icu.fr.yaml index db1ad1f50fa0a2877e27bf50441fa77f58858924..041ec03e54f7fb240416dfcc239a6856173d64bc 100644 --- a/webapp/translations/validators+intl-icu.fr.yaml +++ b/webapp/translations/validators+intl-icu.fr.yaml @@ -1,3 +1,4 @@ +common.validator.help.password.error.password-must-match: 'Les champs du mot de passe doivent correspondre.' common.validator.help.password.error.new-password-must-match: 'Les champs du nouveau mot de passe doivent correspondre.' common.validator.help.email.error.not-valid: 'Veuillez saisir une adresse email valide.' common.validator.help.password.error.too-short: 'La taille du mot de passe est trop petite.'