From a6df6cbf0c49024af29fc27f34da603495796d22 Mon Sep 17 00:00:00 2001
From: Frank
Date: Wed, 14 Jan 2026 13:09:32 +0100
Subject: [PATCH] Request resend of verification mail
---
src/Tech/Controller/ActivationController.php | 2 +-
.../Controller/RegistrationController.php | 39 +++++++++++++++++++
.../Form/ResendVerificationEmailFormType.php | 34 ++++++++++++++++
src/Tech/Service/UserChecker.php | 3 +-
.../registration/confirmation_email.html.twig | 1 +
.../resend_verification_email.html.twig | 17 ++++++++
templates/tech/security/login.html.twig | 10 ++++-
7 files changed, 103 insertions(+), 3 deletions(-)
create mode 100644 src/Tech/Form/ResendVerificationEmailFormType.php
create mode 100644 templates/tech/registration/resend_verification_email.html.twig
diff --git a/src/Tech/Controller/ActivationController.php b/src/Tech/Controller/ActivationController.php
index f467829..c2dcc3b 100644
--- a/src/Tech/Controller/ActivationController.php
+++ b/src/Tech/Controller/ActivationController.php
@@ -31,7 +31,7 @@ class ActivationController extends AbstractController
try {
$emailVerifier->handleEmailConfirmation($request, $user);
} catch (VerifyEmailExceptionInterface $exception) {
- $this->addFlash('error', $exception->getReason());
+ $this->addFlash('error', $exception->getReason() . ' If the link has expired, you can request a new one here.');
return $this->redirectToRoute('app_register');
}
diff --git a/src/Tech/Controller/RegistrationController.php b/src/Tech/Controller/RegistrationController.php
index 7cb2d20..55d29f6 100644
--- a/src/Tech/Controller/RegistrationController.php
+++ b/src/Tech/Controller/RegistrationController.php
@@ -4,6 +4,8 @@ namespace App\Tech\Controller;
use App\Tech\Entity\User;
use App\Tech\Form\RegistrationFormType;
+use App\Tech\Form\ResendVerificationEmailFormType;
+use App\Tech\Repository\UserRepository;
use App\Tech\Service\EmailVerifier;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
@@ -54,4 +56,41 @@ class RegistrationController extends AbstractController
'registrationForm' => $form->createView(),
]);
}
+
+ #[Route('/verify/resend', name: 'app_verify_resend_email')]
+ public function resendVerificationEmail(Request $request, UserRepository $userRepository, EmailVerifier $emailVerifier): Response
+ {
+ $form = $this->createForm(ResendVerificationEmailFormType::class);
+ $form->handleRequest($request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $email = $form->get('email')->getData();
+ $user = $userRepository->findOneBy(['email' => $email]);
+
+ if ($user) {
+ if (!$user->isVerified()) {
+ $emailVerifier->sendEmailConfirmation('app_verify_email', $user,
+ (new TemplatedEmail())
+ ->from($this->getParameter('mailer_from'))
+ ->to($user->getEmail())
+ ->subject('Please Confirm your Email')
+ ->htmlTemplate('tech/registration/confirmation_email.html.twig')
+ );
+ } else {
+ $this->addFlash('info', 'This email address is already verified.');
+ return $this->redirectToRoute('app_login');
+ }
+ }
+
+ // We show the same success message regardless of whether the user exists or not,
+ // to avoid revealing whether an email is registered.
+ $this->addFlash('success', 'If an account exists with this email, a new confirmation link has been sent.');
+
+ return $this->redirectToRoute('website_home');
+ }
+
+ return $this->render('tech/registration/resend_verification_email.html.twig', [
+ 'resendForm' => $form->createView(),
+ ]);
+ }
}
diff --git a/src/Tech/Form/ResendVerificationEmailFormType.php b/src/Tech/Form/ResendVerificationEmailFormType.php
new file mode 100644
index 0000000..e1d5d17
--- /dev/null
+++ b/src/Tech/Form/ResendVerificationEmailFormType.php
@@ -0,0 +1,34 @@
+add('email', EmailType::class, [
+ 'constraints' => [
+ new NotBlank([
+ 'message' => 'Please enter your email',
+ ]),
+ new Email([
+ 'message' => 'Please enter a valid email address',
+ ]),
+ ],
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setDefaults([]);
+ }
+}
diff --git a/src/Tech/Service/UserChecker.php b/src/Tech/Service/UserChecker.php
index 11a621e..66d6558 100644
--- a/src/Tech/Service/UserChecker.php
+++ b/src/Tech/Service/UserChecker.php
@@ -3,6 +3,7 @@
namespace App\Tech\Service;
use App\Tech\Entity\User;
+use Symfony\Component\Security\Core\Exception\AccountStatusException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
@@ -16,7 +17,7 @@ class UserChecker implements UserCheckerInterface
}
if (!$user->isVerified()) {
- throw new CustomUserMessageAuthenticationException('Your email address is not verified.');
+ throw new CustomUserMessageAuthenticationException('Your email address is not verified.', ['%resend_link%' => '/verify/resend']);
}
}
diff --git a/templates/tech/registration/confirmation_email.html.twig b/templates/tech/registration/confirmation_email.html.twig
index bc307f2..b256fa1 100644
--- a/templates/tech/registration/confirmation_email.html.twig
+++ b/templates/tech/registration/confirmation_email.html.twig
@@ -4,6 +4,7 @@
Please confirm your email address by clicking the following link:
Confirm my Email.
This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}.
+ If the link has expired or doesn't work, you can request a new one.
diff --git a/templates/tech/registration/resend_verification_email.html.twig b/templates/tech/registration/resend_verification_email.html.twig
new file mode 100644
index 0000000..556e1f2
--- /dev/null
+++ b/templates/tech/registration/resend_verification_email.html.twig
@@ -0,0 +1,17 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}Resend verification email{% endblock %}
+
+{% block body %}
+
Resend verification email
+
+
Enter your email address and we will send you a new link to verify your account.