<?php
namespace App\Controller\Web;
use App\Entity\User;
use App\Form\Resetting\ResetPasswordFormType;
use App\Form\Resetting\ResetPasswordRequestFormType;
use DateTime;
use Exception;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
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\Address;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Contracts\Translation\TranslatorInterface;
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="app_login")
* @param Request $request
* @param AuthenticationUtils $authenticationUtils
* @return Response
*/
public function login(Request $request, AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('index_presentation');
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('Security/login.html.twig', [
'last_username' => $lastUsername,
'error' => $error
]);
}
/**
* @Route("/logout", name="app_logout", options = { "expose" = true }, methods={"GET","HEAD"})
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
/**
* @Route("/resetting/request", name="app_password_reset_request", options={"expose":true})
* @param Request $request
* @param MailerInterface $mailer
* @param TranslatorInterface $translator
* @return Response
*/
public function resetPasswordRequest(Request $request, MailerInterface $mailer, TranslatorInterface $translator) : Response {
$form = $this->createForm(ResetPasswordRequestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository(User::class)->findOneBy(array('email' => $form->get('email')->getData()));
if ($user) {
if (empty($user->getConfirmationToken())) {
try {
$user->setConfirmationToken(md5(random_bytes(random_int(40, 50))));
} catch (Exception $e) {
}
}
$latestRequestDate = $user->getPasswordRequestedAt();
$now = new DateTime();
$diff = $now->getTimestamp() - ($latestRequestDate ? $latestRequestDate->getTimestamp() : 0);
if (is_null($latestRequestDate) || $diff >= 86400) {
$user->setPasswordRequestedAt(new DateTime());
if ($this->SendResetPasswordEmail($mailer, $translator, $user)) {
// TODO change email with the link
$em->flush();
} else {
// TODO display if there is an error for the sending of the mail
}
} else if ($diff < 86400) {
return $this->render('Resetting/passwordAlreadyRequested.html.twig', [
'email' => $form->get('email')->getData(),
]);
}
}
return $this->render('Resetting/check_email.html.twig', [
'email' => $form->get('email')->getData(),
]);
}
return $this->render('Resetting/request.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @Route("/resetting/password", name="app_password_reset", options={"expose":true})
* @param Request $request
* @param UserPasswordEncoderInterface $passwordEncoder
* @return Response
*/
public function resetPassword(Request $request, UserPasswordEncoderInterface $passwordEncoder) : Response {
$form = $this->createForm(ResetPasswordFormType::class);
$em = $this->getDoctrine()->getManager();
$form->handleRequest($request);
$user = null;
if ($form->isSubmitted() && $form->isValid()) {
$user = $em->getRepository(User::class)->findOneBy(array('confirmationToken' => $request->get('token')));
if ($user && $user->getPasswordRequestedAt()) {
$now = new DateTime();
if (($now->getTimestamp() - $user->getPasswordRequestedAt()->getTimestamp()) > 86400) {
return $this->render('Resetting/passwordRequestError.html.twig', [
]);
}
$user->setPassword(
$passwordEncoder->encodePassword(
$user,
$form->get('plainPassword')->getData()
)
);
$user->setPasswordRequestedAt(null);
$em->flush();
} else {
return $this->render('Resetting/passwordRequestError.html.twig', [
]);
}
return $this->redirectToRoute('app_login');
} else if (!$form->isSubmitted()) {
$user = $em->getRepository(User::class)->findOneBy(array('confirmationToken' => $request->get('token')));
if ($user && $user->getPasswordRequestedAt()) {
$now = new DateTime();
if (($now->getTimestamp() - $user->getPasswordRequestedAt()->getTimestamp()) > 86400) {
return $this->render('Resetting/passwordRequestError.html.twig', [
]);
}
} else {
return $this->render('Resetting/passwordRequestError.html.twig', [
]);
}
}
return $this->render('Resetting/reset.html.twig', [
'form' => $form->createView(), 'token' => $request->get('token')
]);
}
private function SendResetPasswordEmail(MailerInterface $mailer, TranslatorInterface $translator, User $user) : bool {
$message = (new TemplatedEmail())
->subject($translator->trans('resetting.email.subject', array(), 'FOSUserBundle'))
->from(new Address($this->getParameter('NOREPLY_EMAIL'), 'No-Reply'))
->to(new Address($user->getEmail(), ($user->getFirstName() . " " . $user->getLastName())))
->htmlTemplate('Resetting/emailResetting.html.twig')
->textTemplate('Resetting/emailResetting.txt.twig')
->context([
'datamail' => [
'user' => $user,
'confirmationUrl' => $this->generateUrl('app_password_reset', [], UrlGeneratorInterface::ABSOLUTE_URL).'?token='.$user->getConfirmationToken()
]
])
;
try {
$mailer->send($message);
} catch (TransportExceptionInterface $e) {
return false;
}
return true;
}
}