<?php
namespace App\Controller;
use App\Entity\FrontUser;
use App\Entity\Page;
use App\Form\ForgotPasswordType;
use App\Form\FrontUser\FrontUserType;
use App\Form\Model\ForgotPassword;
use App\Form\Model\ResetPassword;
use App\Form\ResetPasswordType;
use App\Repository\FrontUserRepository;
use App\Service\MailService;
use App\Utils\FormHelper;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\Persistence\ManagerRegistry;
use Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
#[Route('')]
class SecurityController extends AbstractController
{
/**
* SecurityController constructor.
*/
public function __construct(
protected MailService $mailer,
private readonly UserPasswordHasherInterface $passwordEncoder,
protected ManagerRegistry $registry,
private readonly MailService $mailService
) {
}
/**
* @throws SyntaxError
* @throws RuntimeError
* @throws LoaderError
*/
#[Route("/registration", name: "front_registration", methods: ["POST"], priority: 10)]
public function registration(Request $request, FrontUserRepository $frontUserRepository): JsonResponse
{
$token = $request->request->get("front_user")["token"];
if ($this->isCsrfTokenValid("front_user_form", $token)) {
$frontUser = new FrontUser();
$form = $this->createForm(FrontUserType::class, $frontUser);
if ('POST' == $request->getMethod()) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$hashedPassword = $this->passwordEncoder->hashPassword(
$frontUser,
$frontUser->getPlainPassword()
);
$frontUser->setRoles(["ROLE_USER"]);
$frontUser->setPassword($hashedPassword);
$frontUserRepository->add($frontUser);
$link = $this->generateUrl('back_frontUser_edit', [
"id" => $frontUser->getId(),
]);
$this->mailService->accountCreationNotification($link);
return $this->json([
"success" => true,
], Response::HTTP_CREATED);
}
return $this->json([
"success" => false,
"errors" => FormHelper::getErrorMessages($form)
], Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->json([
"success" => false,
"message" => "Method Not Allowed."
], Response::HTTP_METHOD_NOT_ALLOWED);
}
return $this->json([
"success" => false,
"message" => "Access Forbidden."
], Response::HTTP_FORBIDDEN);
}
#[Route("/connexion", name: "front_security_login", priority: 10)]
public function login(AuthenticationUtils $authenticationUtils): Response
{
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
$page = $this->registry->getRepository(Page::class)->findOneSingleByType("login");
return $this->render('front/layout/login.html.twig', [
'last_username' => $lastUsername,
'error' => $error,
'page' => $page
]);
}
/**
* @throws NonUniqueResultException
* @throws LoaderError
* @throws RuntimeError
* @throws SyntaxError
*/
#[Route('/mot-de-passe/oublie', name: 'front_security_forgot_password', priority: 10)]
public function forgotPassword(Request $request): Response
{
$error = null;
$success = null;
$forgotPassword = new ForgotPassword();
$form = $this->createForm(ForgotPasswordType::class, $forgotPassword);
if ('POST' == $request->getMethod()) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$mail = $forgotPassword->getEmail();
/** @var FrontUserRepository $repository */
$repository = $this->registry->getRepository(FrontUser::class);
/** @var FrontUser $user */
$user = $repository->findOneByMail($mail);
$success = false;
if (null !== $user) {
$user->generateResetPasswordHash();
$em = $this->registry->getManager();
$em->persist($user);
$em->flush();
$this->mailer->resetFrontPassword($user);
$success = true;
}
}
$error = FormHelper::getErrorMessages($form);
if (isset($error['forgot_password[email]'])) {
$error = $error['forgot_password[email]'][0];
}
}
$form = FormHelper::getData($form);
$page = $this->registry->getRepository(Page::class)->findOneSingleByType("forgot-password");
return $this->render('front/layout/forgot-password.html.twig', [
'form' => $form['forgot_password']['children'],
'error' => $error ?? null,
'page' => $page,
'success' => $success ?? null
]);
}
#[Route('/mot-de-passe/reinitialisation/{resetPasswordHash}', name: 'front_security_reset_password', priority: 10)]
public function resetPassword(Request $request, FrontUser $user): Response
{
$error = null;
$resetPassword = new ResetPassword();
$form = $this->createForm(ResetPasswordType::class, $resetPassword);
if ('POST' == $request->getMethod()) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->registry->getManager();
$user->setPassword($this->passwordEncoder->hashPassword($user, $resetPassword->getPassword()));
$user->setResetPasswordHash(null);
$em->persist($user);
$em->flush();
return new RedirectResponse($this->generateUrl('front_security_login'));
}
$error = FormHelper::getErrorMessages($form);
if (isset($error['reset_password[password]']['reset_password[password][first]'])) {
$error = $error['reset_password[password]']['reset_password[password][first]'][0];
} elseif (isset($error['reset_password[password]']['reset_password[password][second]'])) {
$error = $error['reset_password[password]']['reset_password[password][second]'][0];
}
}
$form = FormHelper::getData($form);
$page = $this->registry->getRepository(Page::class)->findOneSingleByType("reset-password");
return $this->render('front/layout/reset-password.html.twig', [
'form' => $form['reset_password']['children'],
'error' => $error ?? null,
'hash' => $user->getResetPasswordHash(),
'page' => $page
]);
}
#[Route('/confirm-mail/{confirmEmailHash}', name: 'front_security_confirmEmail')]
public function confirmEmail(FrontUser $user): Response
{
$em = $this->registry->getManager();
$user->setConfirmEmail(true);
$user->setConfirmEmailHash();
$em->persist($user);
$em->flush();
return new RedirectResponse($this->generateUrl('front_security_login'));
}
/**
* @throws \Exception
*/
#[Route('/logout', name: 'front_security_logout')]
public function logout(): never
{
throw new Exception('This should never be reached!');
}
}