<?php
namespace App\Controller;
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class SecurityController extends AbstractController
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* @Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils, Request $request): Response
{
$this->logger->info('Login page accessed', [
'method' => $request->getMethod(),
'host' => $request->getHost()
]);
// Si l'utilisateur est déjà connecté
if ($this->getUser()) {
$this->logger->info('User already logged in', [
'user' => $this->getUser()->getUserIdentifier(),
'roles' => $this->getUser()->getRoles()
]);
// Si on est sur flexenergie.pro et que l'utilisateur a le rôle ROLE_CLIENT_PRO
if (str_contains($request->getHost(), 'flexenergie.pro') &&
in_array('ROLE_CLIENT_PRO', $this->getUser()->getRoles())) {
return $this->redirectToRoute('pro_dashboard');
}
// Sinon, redirection par défaut
return $this->redirectToRoute('app_home');
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
if ($error) {
$this->logger->warning('Login error', ['error' => $error->getMessage()]);
}
// Déterminer quel template utiliser selon le domaine
$template = str_contains($request->getHost(), 'flexenergie.pro')
? 'security/pro_login.html.twig'
: 'security/login.html.twig';
return $this->render($template, [
'last_username' => $lastUsername,
'error' => $error,
'is_pro_site' => str_contains($request->getHost(), 'flexenergie.pro')
]);
}
/**
* @Route("/logout", name="app_logout")
*/
public function logout(): void
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
/**
* @Route("/password-reset", name="app_password_reset")
*/
public function resetPassword(Request $request)
{
$this->logger->info('Password reset route called', [
'method' => $request->getMethod(),
'query' => $request->query->all(),
'headers' => $request->headers->all()
]);
$email = $request->query->get('email');
$this->logger->info('Email from request', ['email' => $email]);
$user = $this->getDoctrine()->getRepository(User::class)->findOneBy(['email' => $email]);
if (!$user) {
$this->logger->info('Password reset attempt for unknown email', ['email' => $email]);
return $this->json([
'success' => false,
'message' => 'Email inconnu'
], 404);
}
$token = bin2hex(random_bytes(32));
$user->setResetToken($token);
$user->setResetTokenExpiresAt(new \DateTime('+1 hour'));
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
$resetUrl = $this->generateUrl('app_reset_password', ['token' => $token], UrlGeneratorInterface::ABSOLUTE_URL);
$mail = (new Email())
->from(new Address('contact@flexenergie.fr', 'FlexEnergie'))
->to($email)
->subject('Réinitialisation de mot de passe')
->html($this->renderView(
'email/reset_password.html.twig',
['resetUrl' => $resetUrl]
));
$this->logger->info('Email prepared', [
'from' => 'contact@flexenergie.fr',
'to' => $email,
'resetUrl' => $resetUrl
]);
try {
// Créer le transport et le mailer comme dans le script de test
$transport = Transport::fromDsn($_ENV['MAILER_DSN']);
$mailer = new Mailer($transport);
$mailer->send($mail);
return $this->json([
'success' => true,
'message' => 'Un e-mail de réinitialisation a été envoyé à votre adresse.'
]);
} catch (\Exception $e) {
$this->logger->error('Failed to send password reset email', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return $this->json([
'success' => false,
'message' => 'Une erreur est survenue lors de l\'envoi de l\'e-mail : ' . $e->getMessage()
], 500);
}
}
/**
* @Route("/reset-password/{token}", name="app_reset_password")
*/
public function resetPasswordForm(Request $request, string $token, UserPasswordEncoderInterface $passwordEncoder)
{
$user = $this->getDoctrine()->getRepository(User::class)->findOneBy(['resetToken' => $token]);
if (!$user || $user->getResetTokenExpiresAt() < new \DateTime()) {
$this->addFlash('reset_password_error', 'Le lien de réinitialisation est invalide ou a expiré.');
return $this->redirectToRoute('app_login');
}
$form = $this->createFormBuilder()
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'first_options' => [
'constraints' => [
new NotBlank([
'message' => 'Veuillez entrer un mot de passe',
]),
new Length([
'min' => 6,
'minMessage' => 'Votre mot de passe doit comporter au moins {{ limit }} caractères',
'max' => 4096,
]),
],
'label' => 'Nouveau mot de passe',
],
'second_options' => [
'label' => 'Répéter le mot de passe',
],
'invalid_message' => 'Les champs du mot de passe doivent correspondre.',
'mapped' => false,
])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$newPassword = $form->get('plainPassword')->getData();
$user->setPassword($passwordEncoder->encodePassword($user, $newPassword));
$user->setResetToken(null);
$user->setResetTokenExpiresAt(null);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash('success', 'Votre mot de passe a été mis à jour avec succès.');
return $this->redirectToRoute('app_login');
}
return $this->render('security/reset_password.html.twig', [
'resetForm' => $form->createView(),
]);
}
/**
* @Route("/password-change", name="app_password_change")
*/
public function changePassword()
{
return $this->render('security/change_password.html.twig');
}
/**
* @Route("/password-update", name="app_password_update")
*/
public function updatePassword(Request $request, UserPasswordEncoderInterface $passwordEncoder, UserInterface $user)
{
$new_password = $request->request->get('new_password');
$user->setPassword($passwordEncoder->encodePassword($user, $new_password));
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash('success', 'Mot de passe mis à jour avec succès.');
return $this->redirectToRoute('app_login');
}
}