diff --git a/migrations/Version20220307154836.php b/migrations/Version20220307154836.php new file mode 100644 index 0000000000000000000000000000000000000000..ac675b329b4a4552cf34075703db1bc7e089494e --- /dev/null +++ b/migrations/Version20220307154836.php @@ -0,0 +1,37 @@ +<?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 Version20220307154836 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('CREATE TABLE `pending_email_address` (id INT AUTO_INCREMENT NOT NULL, user INT NOT NULL, email VARCHAR(255) NOT NULL, INDEX IDX_621FD0118D93D649 (user), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE `pending_email_address` ADD CONSTRAINT FK_621FD0118D93D649 FOREIGN KEY (user) REFERENCES `user` (id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE `pending_email_address`'); + $this->addSql('ALTER TABLE capsule CHANGE nom nom VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE link link VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE edition_link edition_link VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE password password VARCHAR(50) NOT NULL COLLATE `utf8_unicode_ci`'); + $this->addSql('ALTER TABLE `group` CHANGE name name VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`'); + $this->addSql('ALTER TABLE invitation_editeur_capsule CHANGE email email VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`'); + $this->addSql('ALTER TABLE reset_password_request CHANGE selector selector VARCHAR(20) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE hashed_token hashed_token VARCHAR(100) NOT NULL COLLATE `utf8_unicode_ci`'); + $this->addSql('ALTER TABLE `user` CHANGE email email VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE email_canonical email_canonical VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE name name VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE firstname firstname VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE username username VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE username_canonical username_canonical VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE roles roles LONGTEXT NOT NULL COLLATE `utf8_unicode_ci` COMMENT \'(DC2Type:json)\', CHANGE password password VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`, CHANGE salt salt VARCHAR(255) NOT NULL COLLATE `utf8_unicode_ci`'); + } +} diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 91b811c04ef6b17f3b9679553607f0f27554735a..a3afb46aecf328392eb5832c567be41140e200b5 100755 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -2,10 +2,13 @@ namespace App\Controller; +use App\Entity\PendingEmailAddress; use App\Entity\User; use App\Form\EditPasswordFormType; use App\Form\EditUserProfileFormType; +use App\Security\EmailVerifier; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -36,7 +39,7 @@ class UserController extends AbstractController } #[Route('/edit_profile', name:'edit_profile')] - public function editProfile(Request $request): Response + public function editProfile(Request $request, EmailVerifier $email_verifier): Response { $current_user = $this->getUser(); @@ -54,17 +57,28 @@ class UserController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { $this->entity_manager->persist($current_user); $this->entity_manager->flush(); - $current_user->setFirstName($form->get('firstName')->getData()); - $current_user->setLastName($form->get('lastName')->getData()); - $this->entity_manager->persist($current_user); - $this->entity_manager->flush(); - $new_email_address = $form->get('email')->getData(); - if ($current_user->getEmail() !== $new_email_address) { + if ($current_user->getEmail() !== $form->get('email')->getData()) { + $pending_email_address = new PendingEmailAddress(); + $pending_email_address->setEmail($form->get('email')->getData()); + $pending_email_address->setUser($current_user); + $this->entity_manager->persist($pending_email_address); + $this->entity_manager->flush(); + + $email_verifier->sendEmailConfirmation( + 'app_verify_email', + $pending_email_address->getUser()->getId(), + $pending_email_address->getEmail(), + (new TemplatedEmail()) + ->to($pending_email_address->getEmail()) + ->subject('Please Confirm your Email') + ->htmlTemplate('user/update_email.html.twig') + ); + $this->addFlash( 'warning', $this->translator->trans('user.profile.updated.warning', [ - 'new_email_address' => $new_email_address + 'new_email_address' => $form->get('email')->getData() ]) ); diff --git a/src/Entity/PendingEmailAddress.php b/src/Entity/PendingEmailAddress.php new file mode 100644 index 0000000000000000000000000000000000000000..3f9a9f34952962a8ca909ecd94dabcc0e0b38876 --- /dev/null +++ b/src/Entity/PendingEmailAddress.php @@ -0,0 +1,45 @@ +<?php + +namespace App\Entity; + +use App\Repository\PendingEmailAddressRepository; +use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; + +#[ORM\Entity(repositoryClass:PendingEmailAddressRepository::class)] +#[ORM\Table(name:'`pending_email_address`')] +class PendingEmailAddress +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type:'integer')] + private int $id; + + #[ORM\ManyToOne(targetEntity:User::class)] + #[ORM\JoinColumn(name:'user', referencedColumnName:'id', nullable:false)] + private User $user; + + #[Assert\Email(message: 'email.valid')] + #[ORM\Column(type:'string', length:255)] + private string $email; + + public function getUser(): User + { + return $this->user; + } + + public function setUser(User $user): void + { + $this->user = $user; + } + + public function getEmail(): string + { + return $this->email; + } + + public function setEmail(string $email): void + { + $this->email = $email; + } +} diff --git a/src/Form/EditUserProfileFormType.php b/src/Form/EditUserProfileFormType.php index a78a51ee2a4858f77e428d08821955e278c23a29..0c41c791a6fd853f0c4d8b82ab220e3b9c358320 100755 --- a/src/Form/EditUserProfileFormType.php +++ b/src/Form/EditUserProfileFormType.php @@ -78,6 +78,5 @@ class EditUserProfileFormType extends AbstractType 'data_class' => User::class, 'current_email_address' => '' ]); -// $resolver->setAllowedTypes('current_email_address', 'string'); } } diff --git a/src/Repository/PendingEmailAddressRepository.php b/src/Repository/PendingEmailAddressRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..78585ce52291d54ae7157b05a785dc221589f3a5 --- /dev/null +++ b/src/Repository/PendingEmailAddressRepository.php @@ -0,0 +1,23 @@ +<?php + +namespace App\Repository; + +use App\Entity\PendingEmailAddress; +use App\Entity\User; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; + +/** + * @method PendingEmailAddress|null find($id, $lockMode = null, $lockVersion = null) + * @method PendingEmailAddress|null findOneBy(array $criteria, array $orderBy = null) + * @method PendingEmailAddress[] findAll() + * @method PendingEmailAddress[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * @template PendingEmailAddress of object + */ +class PendingEmailAddressRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, PendingEmailAddress::class); + } +} diff --git a/templates/user/update_email.html.twig b/templates/user/update_email.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..e292b58605c166bf66848f241acff2c0181ead73 --- /dev/null +++ b/templates/user/update_email.html.twig @@ -0,0 +1,17 @@ +<h1> + {{ 'user.edit.email.title'|trans }} +</h1> + +<p> + {{ 'user.edit.email.text'|trans }}: + <br><br> + <a href="{{ signedUrl }}"> + {{ 'user.edit.email.confirm_email'|trans }} + </a> + {{ 'general.link_expire'|trans({'%expirationDuration%': + expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle')}) }} +</p> + +<p> + {{ 'general.greeting'|trans }} +</p> diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index 012af5a9acc861991c1324ed1713bcd8035a9f32..215c4aa2fbecf48ac3bb7f0656954435c6e797ea 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -119,6 +119,11 @@ user: edit_profile: Edit my profile edit_password: Edit my password edit_email_address: Edit my email address + edit: + email: + title: Hi! Please confirm your email + text: Please click the following link to update your user account and for now on use this email address. + confirm_email: Confirm my email editors: title: Editors diff --git a/translations/messages.fr.yaml b/translations/messages.fr.yaml index b2e4e2695140508c1a3e11e8116608e110865dab..63e962c302519a570dd7305d7a22296d7eb0924b 100644 --- a/translations/messages.fr.yaml +++ b/translations/messages.fr.yaml @@ -117,6 +117,11 @@ user: edit_profile: Modifier mon mot de passe edit_password: Modifier mon mot de passe edit_email_address: Modifier mon adresse e-mail + edit: + email: + title: Bonjour ! Veuillez confirmer votre adresse email + text: Veuillez cliquer sur le lien suivant pour mettre à jour votre profil utilisateur et utiliser dorénavant cette adresse e-mail. + confirm_email: Confirmer mon adresse e-mail editors: title: Editeurs d'une capsule