Fix sign up and sign in forms

master
Julien Rosset 1 year ago
parent 34fc4a466c
commit b9aed93c9d

@ -37,7 +37,7 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ### ###< symfony/messenger ###
###> symfony/mailer ### ###> symfony/mailer ###
# MAILER_DSN=null://null MAILER_DSN=smtp://localhost:1025 # MailHog
MAILER_EMAIL=jul.rosset@gmail.com MAILER_EMAIL=jul.rosset@gmail.com
MAILER_NAME="WebEDM Mail Bot" MAILER_NAME="WebEDM Mail Bot"
###< symfony/mailer ### ###< symfony/mailer ###

2
.gitignore vendored

@ -24,3 +24,5 @@
/public/assets/ /public/assets/
/assets/vendor/ /assets/vendor/
###< symfony/asset-mapper ### ###< symfony/asset-mapper ###
.symfony.local.yaml

@ -5,16 +5,12 @@
//$primary : rgb(0, 0, 0); //$primary : rgb(0, 0, 0);
//$secondary : rgb(102, 102, 102); //$secondary : rgb(102, 102, 102);
//endregion
//region Autres variables Bootstrap
$alert-padding-y : 0.25rem; $alert-padding-y : 0.25rem;
$alert-padding-x : 0.25rem; $alert-padding-x : 0.25rem;
$alert-margin-bottom : 0.5rem; $alert-margin-bottom : 0.5rem;
//endregion //endregion
//region Autres variables Bootstrap
$enable-rounded : false;
$nav-link-padding-y : 0;
$box-shadow : 0px 3px 15px 0 rgba(0, 0, 0, .8);
//endregion
//region Les autres variables de Boostrap //region Les autres variables de Boostrap
@import '../../vendor/twbs/bootstrap/scss/variables'; @import '../../vendor/twbs/bootstrap/scss/variables';
@import '../../vendor/twbs/bootstrap/scss/variables-dark'; @import '../../vendor/twbs/bootstrap/scss/variables-dark';

@ -4,49 +4,50 @@
"minimum-stability": "stable", "minimum-stability": "stable",
"prefer-stable": true, "prefer-stable": true,
"require": { "require": {
"php": ">=8.1", "php": ">=8.1",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*", "ext-iconv": "*",
"doctrine/annotations": "^2.0", "doctrine/annotations": "^2.0",
"doctrine/doctrine-bundle": "^2.9", "doctrine/dbal": "^3",
"doctrine/doctrine-bundle": "^2.9",
"doctrine/doctrine-migrations-bundle": "^3.2", "doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.15", "doctrine/orm": "^2.15",
"phpdocumentor/reflection-docblock": "^5.3", "phpdocumentor/reflection-docblock": "^5.3",
"phpstan/phpdoc-parser": "^1.20", "phpstan/phpdoc-parser": "^1.20",
"stof/doctrine-extensions-bundle": "^1.7", "stof/doctrine-extensions-bundle": "^1.7",
"symfony/asset": "6.4.*", "symfony/asset": "6.4.*",
"symfony/asset-mapper": "6.4.*", "symfony/asset-mapper": "6.4.*",
"symfony/console": "6.4.*", "symfony/console": "6.4.*",
"symfony/doctrine-messenger": "6.4.*", "symfony/doctrine-messenger": "6.4.*",
"symfony/dotenv": "6.4.*", "symfony/dotenv": "6.4.*",
"symfony/expression-language": "6.4.*", "symfony/expression-language": "6.4.*",
"symfony/flex": "^2", "symfony/flex": "^2",
"symfony/form": "6.4.*", "symfony/form": "6.4.*",
"symfony/framework-bundle": "6.4.*", "symfony/framework-bundle": "6.4.*",
"symfony/http-client": "6.4.*", "symfony/http-client": "6.4.*",
"symfony/intl": "6.4.*", "symfony/intl": "6.4.*",
"symfony/mailer": "6.4.*", "symfony/mailer": "6.4.*",
"symfony/mime": "6.4.*", "symfony/mime": "6.4.*",
"symfony/monolog-bundle": "^3.0", "symfony/monolog-bundle": "^3.0",
"symfony/notifier": "6.4.*", "symfony/notifier": "6.4.*",
"symfony/process": "6.4.*", "symfony/process": "6.4.*",
"symfony/property-access": "6.4.*", "symfony/property-access": "6.4.*",
"symfony/property-info": "6.4.*", "symfony/property-info": "6.4.*",
"symfony/rate-limiter": "6.4.*", "symfony/rate-limiter": "6.4.*",
"symfony/runtime": "6.4.*", "symfony/runtime": "6.4.*",
"symfony/security-bundle": "6.4.*", "symfony/security-bundle": "6.4.*",
"symfony/serializer": "6.4.*", "symfony/serializer": "6.4.*",
"symfony/string": "6.4.*", "symfony/string": "6.4.*",
"symfony/translation": "6.4.*", "symfony/translation": "6.4.*",
"symfony/twig-bundle": "6.4.*", "symfony/twig-bundle": "6.4.*",
"symfony/validator": "6.4.*", "symfony/validator": "6.4.*",
"symfony/web-link": "6.4.*", "symfony/web-link": "6.4.*",
"symfony/yaml": "6.4.*", "symfony/yaml": "6.4.*",
"symfonycasts/sass-bundle": "^0.6.0", "symfonycasts/sass-bundle": "^0.6.0",
"symfonycasts/verify-email-bundle": "^1.17", "symfonycasts/verify-email-bundle": "^1.17",
"twbs/bootstrap": "^5.3", "twbs/bootstrap": "^5.3",
"twig/extra-bundle": "^3.0", "twig/extra-bundle": "^3.0",
"twig/twig": "^3.0" "twig/twig": "^3.0"
}, },
"config": { "config": {
"allow-plugins": { "allow-plugins": {

@ -1,5 +1,6 @@
twig: twig:
default_path: '%kernel.project_dir%/templates' default_path: '%kernel.project_dir%/templates'
form_themes: [ 'bootstrap_5_horizontal_layout.html.twig' ]
when@test: when@test:
twig: twig:

@ -4,8 +4,8 @@
# Put parameters here that don't need to change on each machine where the app is deployed # Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters: parameters:
mailer.email: '%env(MAILER_EMAIL)%)' mailer.email: '%env(MAILER_EMAIL)%'
mailer.name: '%env(MAILER_NAME)%)' mailer.name: '%env(MAILER_NAME)%'
services: services:
# default configuration for services in *this* file # default configuration for services in *this* file

@ -0,0 +1,27 @@
<?php
declare(strict_types = 1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240514155807 extends AbstractMigration {
public function getDescription (): string {
return '';
}
public function up (Schema $schema): void {
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user ADD is_verified tinyint(1) NOT NULL');
}
public function down (Schema $schema): void {
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user DROP is_verified');
}
}

@ -58,7 +58,7 @@ class UserController extends AbstractController {
$user->setPassword( $user->setPassword(
$userPasswordHasher->hashPassword( $userPasswordHasher->hashPassword(
$user, $user,
$form->get('plainPassword')->getData() $form->get('newPassword')->getData()
) )
); );
@ -70,10 +70,11 @@ class UserController extends AbstractController {
'user_mailVerify', 'user_mailVerify',
$user, $user,
(new TemplatedEmail()) (new TemplatedEmail())
->from(new Address( ->from(
$this->getParameter('mailer.email'), new Address(
$this->getParameter('mailer.name') $this->getParameter('mailer.email'),
) $this->getParameter('mailer.name')
)
) )
->to($user->getEmail()) ->to($user->getEmail())
->subject('Please Confirm your Email') ->subject('Please Confirm your Email')

@ -32,7 +32,6 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface {
* @var string The hashed password * @var string The hashed password
*/ */
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
#[Assert\NotBlank]
private string $password; private string $password;
/** /**
@ -50,7 +49,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface {
/** /**
* @var Collection<int, Tag> The {@see Tag tags} of the user * @var Collection<int, Tag> The {@see Tag tags} of the user
*/ */
#[ORM\OneToMany(mappedBy: 'user', targetEntity: Tag::class, orphanRemoval: true)] #[ORM\OneToMany(mappedBy: 'owner', targetEntity: Tag::class, orphanRemoval: true)]
#[Assert\Valid] #[Assert\Valid]
private Collection $tags; private Collection $tags;
@ -150,7 +149,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface {
* @see UserInterface * @see UserInterface
*/ */
public function getUserIdentifier (): string { public function getUserIdentifier (): string {
return (string)$this->email; return $this->email;
} }
/** /**
@ -183,7 +182,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface {
* *
* @see UserInterface * @see UserInterface
*/ */
public function eraseCredentials () { public function eraseCredentials (): void {
} }
/** /**
@ -221,12 +220,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface {
* @return $this * @return $this
*/ */
public function removeTag (Tag $tag): static { public function removeTag (Tag $tag): static {
if ($this->tags->removeElement($tag)) { $this->tags->removeElement($tag);
if ($tag->getOwner() === $this) {
$tag->setOwner(null);
}
}
return $this; return $this;
} }

@ -6,6 +6,7 @@ use App\Entity\User;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\IsTrue; use Symfony\Component\Validator\Constraints\IsTrue;
@ -33,22 +34,13 @@ class SignUpFormType extends AbstractType {
public function buildForm (FormBuilderInterface $builder, array $options): void { public function buildForm (FormBuilderInterface $builder, array $options): void {
$builder $builder
->add('email') ->add('email')
->add('agreeTerms', CheckboxType::class, [ ->add('newPassword', RepeatedType::class, [
'mapped' => false,
'constraints' => [
new IsTrue(
[
'message' => 'You should agree to our terms.',
]
),
],
])
->add('plainPassword', PasswordType::class, [
// instead of being set onto the object directly, // instead of being set onto the object directly,
// this is read and encoded in the controller // this is read and encoded in the controller
'mapped' => false, 'type' => PasswordType::class,
'attr' => ['autocomplete' => 'new-password'], 'mapped' => false,
'constraints' => [ 'attr' => ['autocomplete' => 'new-password'],
'constraints' => [
new NotBlank( new NotBlank(
[ [
'message' => 'Please enter a password', 'message' => 'Please enter a password',
@ -63,6 +55,22 @@ class SignUpFormType extends AbstractType {
] ]
), ),
], ],
'first_options' => [
'label' => 'Password',
],
'second_options' => [
'label' => 'Password confirmation',
],
])
->add('agreeTerms', CheckboxType::class, [
'mapped' => false,
'constraints' => [
new IsTrue(
[
'message' => 'You should agree to our terms.',
]
),
],
]); ]);
} }
} }

@ -19,6 +19,9 @@ class UserChecker implements UserCheckerInterface {
return; return;
} }
if (!$user->isVerified()) {
throw new CustomUserMessageAccountStatusException('Your account mail has not been validated.');
}
if ($user->getValidationAdministrator() === null || $user->getValidationDate() === null) { if ($user->getValidationAdministrator() === null || $user->getValidationDate() === null) {
throw new CustomUserMessageAccountStatusException('Your account has not been validated by an administrator yet.'); throw new CustomUserMessageAccountStatusException('Your account has not been validated by an administrator yet.');
} }

@ -7,14 +7,14 @@
<nav class="navbar-light d-flex flex-column justify-content-start fixed-top"> <nav class="navbar-light d-flex flex-column justify-content-start fixed-top">
<div class="d-flex justify-content-between w-100 px-2"> <div class="d-flex justify-content-between w-100 px-2">
<!--region Website name--> <!--region Website name-->
<a class="navbar-brand" href="/"> <a class="navbar-brand" href="{{ path('core_main') }}">
Web EDM Web EDM
</a> </a>
<!--endregion--> <!--endregion-->
<!--region menu--> <!--region menu-->
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<a href="#" class="me-3">Sign In</a> <a href="{{ path('user_signIn') }}" class="me-3">Sign In</a>
<a href="#" class="me-3">Sign Up</a> <a href="{{ path('user_signUp') }}" class="me-3">Sign Up</a>
</div> </div>
<!--endregion--> <!--endregion-->
</div> </div>

@ -5,5 +5,5 @@
{% block mainContent %} {% block mainContent %}
<h1>Web EDM</h1> <h1>Web EDM</h1>
<p>Welcome on Web EDM, the Web Electronic Document Manager.</p> <p>Welcome on Web EDM, the Web Electronic Document Manager.</p>
<p>Please <a href="#">Sign In</a> or <a href="#">Sign out</a> to start.</p> <p>Please <a href="{{ path('user_signIn') }}">Sign In</a> or <a href="{{ path('user_signUp') }}">Sign Up</a> to start.</p>
{% endblock %} {% endblock %}

@ -14,7 +14,7 @@
{% endblock %} {% endblock %}
{% block bodyTag %} {% block bodyTag %}
<body id="page-{{ app.current_route }}"> <body id="page-{{ app.current_route }}" class="m-2">
{% endblock %} {% endblock %}
{% block bodyContent %} {% block bodyContent %}
{% block headerTag %} {% block headerTag %}

@ -6,26 +6,32 @@
<h1>Sign in</h1> <h1>Sign in</h1>
<form method="post"> <form method="post">
{% if error %} {% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div> <div class="mb-3 alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %} {% endif %}
<label for="username">Email</label> <div class="mb-3 row">
<input type="email" value="{{ last_username }}" name="_username" id="username" class="form-control" autocomplete="email" required autofocus> <label for="username" class="col-form-label col-sm-2">Email</label>
<div class="col-sm-10">
<label for="password">Password</label> <input type="email" value="{{ last_username }}" name="_username" id="username" class="form-control" autocomplete="email" required autofocus>
<input type="password" name="_password" id="password" class="form-control" autocomplete="current-password" required> </div>
</div>
<input type="hidden" name="_csrf_token" <div class="mb-3 row">
value="{{ csrf_token('authenticate') }}" <label for="password" class="col-form-label col-sm-2">Password</label>
> <div class="col-sm-10">
<input type="password" name="_password" id="password" class="form-control" autocomplete="current-password" required>
<div class="checkbox mb-3"> </div>
<label> </div>
<input type="checkbox" name="_remember_me" id="remember_me"> <div class="mb-3 row">
<label for="remember_me">Remember me</label> <div class="col-sm-2"></div>
</label> <div class="col-sm-10">
<div class="form-check">
<input type="checkbox" name="_remember_me" id="remember_me" class="form-check-input">
<label for="remember_me" class="form-check-label">Remember me</label>
</div>
</div>
</div> </div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<button class="btn btn-lg btn-primary" type="submit">Sign in</button> <button class="btn btn-lg btn-primary" type="submit">Sign in</button>
</form> </form>
{% endblock %} {% endblock %}

@ -4,9 +4,8 @@
{% block mainContent %} {% block mainContent %}
<h1>Sign up</h1> <h1>Sign up</h1>
<p> <p>
NOTE : after confirming your account email, it must be also validated by an administrator <strong>NOTE :</strong> after confirming your account email, it must be also validated by an administrator
<br>You'll receive an email when your account would be accepted <br>You'll receive an email when your account would be accepted
</p> </p>
@ -14,11 +13,9 @@
{{ form_start(registrationForm) }} {{ form_start(registrationForm) }}
{{ form_row(registrationForm.email) }} {{ form_row(registrationForm.email) }}
{{ form_row(registrationForm.plainPassword, { {{ form_row(registrationForm.newPassword) }}
label: 'Password'
}) }}
{{ form_row(registrationForm.agreeTerms) }} {{ form_row(registrationForm.agreeTerms) }}
<button type="submit" class="btn">Request account</button> <button type="submit" class="btn btn-primary">Request account</button>
{{ form_end(registrationForm) }} {{ form_end(registrationForm) }}
{% endblock %} {% endblock %}

Loading…
Cancel
Save