diff --git a/.env b/.env index ad3c6b8..09f35e3 100644 --- a/.env +++ b/.env @@ -37,5 +37,5 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 ###< symfony/messenger ### ###> symfony/mailer ### -MAILER_DSN=smtp://no-reply@lidge.fr:t7qbPx6C1XDSWbO3XOFf@mail.lidge.fr:587 +MAILER_DSN=smtp://leroyjohan3@gmail.com:nfqvxtdxixrtjrmt@smtp.gmail.com:587 ###< symfony/mailer ### diff --git a/.idea/php.xml b/.idea/php.xml index 91ab0f3..855e17f 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -150,7 +150,7 @@ - + diff --git a/.idea/sortir.iml b/.idea/sortir.iml index 0fa7baa..cf93744 100644 --- a/.idea/sortir.iml +++ b/.idea/sortir.iml @@ -3,6 +3,7 @@ + diff --git a/composer.json b/composer.json index 5493b47..57d57ff 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "minimum-stability": "stable", "prefer-stable": true, "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-ctype": "*", "ext-iconv": "*", "doctrine/dbal": "^3", diff --git a/composer.lock b/composer.lock index bf2178f..e681eea 100644 --- a/composer.lock +++ b/composer.lock @@ -10273,7 +10273,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=8.1", + "php": ">=8.2", "ext-ctype": "*", "ext-iconv": "*" }, diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 7eedffd..d161141 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -43,6 +43,7 @@ security: # Note: Only the *first* access control that matches will be used access_control: - { path: ^/login, roles: PUBLIC_ACCESS } + - { path: ^/password, roles: PUBLIC_ACCESS } - { path: ^/register, roles: PUBLIC_ACCESS } - { path: ^/admin, roles: ROLE_ADMIN } - { path: ^/, roles: ROLE_USER } diff --git a/src/Controller/AdminController.php b/src/Controller/AdminController.php index c25d77d..b3608e4 100644 --- a/src/Controller/AdminController.php +++ b/src/Controller/AdminController.php @@ -3,6 +3,7 @@ namespace App\Controller; use App\Entity\Participant; +use App\Entity\PasswordResetToken; use App\Entity\Site; use App\Entity\Ville; use App\Repository\ParticipantRepository; @@ -10,13 +11,14 @@ use App\Repository\SiteRepository; use App\Repository\VilleRepository; use Doctrine\ORM\EntityManagerInterface; 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\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Email; use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class AdminController extends AbstractController { @@ -85,7 +87,7 @@ class AdminController extends AbstractController return $this->redirectToRoute('app_adminUser'); // Redirigez vers la liste des utilisateurs } #[Route('/admin/user/add', name: 'app_adminUserAdd', methods: ['POST'])] - public function userAdd(Request $request, EntityManagerInterface $entityManager, MailerInterface $mailer): Response + public function userAdd(Request $request, EntityManagerInterface $entityManager, MailerInterface $mailer, UrlGeneratorInterface $urlGenerator): Response { try { // Récupérer les données envoyées par le formulaire @@ -107,7 +109,6 @@ class AdminController extends AbstractController return $this->redirectToRoute('app_adminUser'); } - // Créer une nouvelle entité City et définir ses propriétés $participant = new Participant(); $participant->setNom($nom); $participant->setPrenom($prenom); @@ -119,19 +120,36 @@ class AdminController extends AbstractController $participant->setRoles(['ROLE_USER']); $participant->setPassword(password_hash("aChanger44!", PASSWORD_BCRYPT)); - // Enregistrer la ville dans la base de données $entityManager->persist($participant); + + // Générer un token unique + $token = bin2hex(random_bytes(32)); + + // Enregistrer le token dans la base de données + $passwordResetToken = new PasswordResetToken(); + $passwordResetToken->setToken($token) + ->setEmail($participant->getEmail()) + ->setCreatedAt(new \DateTime()); + + $entityManager->persist($passwordResetToken); $entityManager->flush(); + // Générer un lien de réinitialisation + $resetLink = $urlGenerator->generate( + 'app_password_reset', + ['token' => $token], + UrlGeneratorInterface::ABSOLUTE_URL + ); + // Envoyer un email de notification $email = (new Email()) - ->from('contact@Sortir.com') - ->to($mail) + ->from('contact@sortir.com') + ->to($participant->getEmail()) ->subject('Sortir.com | Bienvenue sur notre site !') ->html("

Bonjour $pseudo,

-

Un administrateur du site vous à créé un compte sur Sortir.com !

-

Votre mot de passe temporaire est : aChanger44!

+

Un administrateur du site vous a créé un compte !

+

Terminer la création de cotre compte : Sortir.com

Toute l'équipe de Sortir vous souhaite la bienvenue !

"); @@ -142,6 +160,9 @@ class AdminController extends AbstractController } catch(\Exception $e) { $this->addFlash('error', "Erreur : " . $e->getMessage()); return $this->redirectToRoute('app_adminUser'); + } catch (TransportExceptionInterface $e) { + $this->addFlash('error', "Erreur : " . $e->getMessage()); + return $this->redirectToRoute('app_adminUser'); } } #[Route('/admin/user/import', name: 'participant_import', methods: ['POST'])] diff --git a/src/Controller/PasswordResetController.php b/src/Controller/PasswordResetController.php new file mode 100644 index 0000000..97e4e18 --- /dev/null +++ b/src/Controller/PasswordResetController.php @@ -0,0 +1,119 @@ +request->get('email'); + + // Vérifier si l'email est valide + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + $this->addFlash('error', 'Adresse e-mail invalide.'); + return $this->redirectToRoute('app_login'); + } + + // Générer un token unique + $token = bin2hex(random_bytes(32)); + + // Enregistrer le token dans la base de données + $passwordResetToken = new PasswordResetToken(); + $passwordResetToken->setToken($token) + ->setEmail($email) + ->setCreatedAt(new \DateTime()); + + $entityManager->persist($passwordResetToken); + $entityManager->flush(); + + // Générer un lien de réinitialisation + $resetLink = $urlGenerator->generate( + 'app_password_reset', + ['token' => $token], + UrlGeneratorInterface::ABSOLUTE_URL + ); + + // Envoyer l'email avec le lien + $email = (new Email()) + ->from('contact@sortir.com') + ->to($email) + ->subject('Sortir.com | Réinitialisation de mot de passe') + ->html("

Bonjour,

Vous avez demandé une réinitialisation de mot de passe. Cliquez sur le lien ci-dessous pour réinitialiser votre mot de passe :

+

Réinitialiser mon mot de passe

+

Ce lien est valable 24 heures.

"); + + $mailer->send($email); + + $this->addFlash('success', 'Un email de réinitialisation a été envoyé.'); + return $this->redirectToRoute('app_login'); + }catch (TransportExceptionInterface|RandomException $e){ + $this->addFlash('error', 'Erreur : ' . $e->getMessage()); + return $this->redirectToRoute('app_login'); + } + } + #[Route('/password/reset/{token}', name: 'app_password_reset', methods: ['GET', 'POST'])] + public function resetPassword( + string $token, + Request $request, + EntityManagerInterface $entityManager, + ): Response { + // Vérifier si le token existe + $repository = $entityManager->getRepository(PasswordResetToken::class); + $passwordResetToken = $repository->findOneBy(['token' => $token]); + + if (!$passwordResetToken || $passwordResetToken->isExpired()) { + $this->addFlash('error', 'Ce lien de réinitialisation est invalide ou expiré.'); + return $this->redirectToRoute('app_login'); + } + + // Si la requête est POST, traiter le nouveau mot de passe + if ($request->isMethod('POST')) { + $newPassword = $request->request->get('password'); + $newPasswordConfirm = $request->request->get('passwordConfirm'); + + if ($newPassword.equalTo($newPasswordConfirm)) { + $this->addFlash('error', 'Les mots de passe ne correspondent pas.'); + return $this->redirectToRoute('app_password_reset', ['token' => $token]); + } + + if (strlen($newPassword) < 6) { + $this->addFlash('error', 'Le mot de passe doit contenir au moins 6 caractères.'); + return $this->redirectToRoute('app_password_reset', ['token' => $token]); + } + + // Récupérer l'utilisateur et mettre à jour le mot de passe + $user = $entityManager->getRepository(Participant::class)->findOneBy(['email' => $passwordResetToken->getEmail()]); + $user->setPassword(password_hash($newPassword, PASSWORD_BCRYPT)); + + $entityManager->remove($passwordResetToken); // Supprimer le token + $entityManager->flush(); + + $this->addFlash('success', 'Votre mot de passe a été mis à jour.'); + return $this->redirectToRoute('app_login'); + } + + return $this->render('password_reset/index.html.twig', ['token' => $token]); + } +} diff --git a/src/DataFixtures/UserFixtures.php b/src/DataFixtures/UserFixtures.php index ccbfa3f..ba62888 100644 --- a/src/DataFixtures/UserFixtures.php +++ b/src/DataFixtures/UserFixtures.php @@ -32,11 +32,11 @@ class UserFixtures extends Fixture $johan->setNom('Leroy'); $johan->setPseudo('Jojo'); $johan->setTelephone('0785421565'); - $johan->setEmail('johan@gmail.com'); + $johan->setEmail('leroyjohan3@gmail.com'); $johan->setRoles(['ROLE_USER', 'ROLE_ADMIN']); $johan->setAdministrateur(true); $johan->setActif(false); - $johan->setPassword($this->userPasswordHasher->hashPassword($johan, 'test-44')); + $johan->setPassword($this->userPasswordHasher->hashPassword($johan, 'Vn21pd%6a%Hw5j')); $manager->persist($johan); $marvin = new Participant(); diff --git a/templates/password_reset/index.html.twig b/templates/password_reset/index.html.twig new file mode 100644 index 0000000..e21a93d --- /dev/null +++ b/templates/password_reset/index.html.twig @@ -0,0 +1,29 @@ +{% extends 'main/base.html.twig' %} +{% block head %} + + + {% block stylesheets %} + {{ encore_entry_link_tags('app') }} + {% endblock %} + +{% endblock %} + +{%block content %} +
+
+

Modifier votre mot de passe !

+
+ + + + +
+ +
+
+
+
+{% endblock %} \ No newline at end of file