<?php
declare(strict_types=1);
namespace Kobizo\Bundle\CoreBundle\Controller;
use Doctrine\ORM\EntityManagerInterface;
use Kobizo\Bundle\CoreBundle\Form\RequestPasswordFormType;
use Kobizo\Bundle\CoreBundle\Form\ResetPasswordFormType;
use Kobizo\Bundle\CoreBundle\Helper\SiteParamsHelper;
use Kobizo\Component\Configuration\MailTemplate\ForgotPasswordMailTemplateConfig;
use Kobizo\Component\Helper\TokenGeneratorInterface;
use Kobizo\Bundle\CoreBundle\Repository\UserRepository;
use Kobizo\Bundle\CoreBundle\Security\LoginFormAuthenticator;
use Kobizo\Component\Provider\MailTemplateProvider;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Kobizo\Component\Resources\AccessControl\DashboardResource;
use Kobizo\Component\Attributes\DefaultRolesAttribute;
use Kobizo\Component\Configuration\Backend\AdminUrlConfig;
/**
* @Route("/password")
*/
class FeResetPasswordController extends KobizoFeAbstractController
{
const TTL_RESET_TIME = 3600;
/**
* @Route("/request", name="app_request_password")
*/
public function sendEmail(
Request $request,
UserRepository $repository,
MailerInterface $mailer,
TokenGeneratorInterface $tokenGenerator,
SiteParamsHelper $siteParamsHelper,
EntityManagerInterface $entityManager,
TranslatorInterface $translator,
MailTemplateProvider $mailTemplateProvider,
ForgotPasswordMailTemplateConfig $forgotPasswordTemplateConfig,
AdminUrlConfig $adminUrlConfig
): Response {
if ($this->isGranted(AuthenticatedVoter::IS_AUTHENTICATED_FULLY)) {
return $this->redirectToRoute('dashboard_analytics', ['admin' => $adminUrlConfig->getValue()]);
}
$form = $this->createForm(RequestPasswordFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$email = $form->get('email')->getData();
$user = $repository->findOneByEmail($email);
if (null !== $user && !$user->isPasswordRequestNoneExpired()) {
if (null === $user->getConfirmationToken()) {
$user->setConfirmationToken($tokenGenerator->generateConfirmationToken($user->getEmail()));
}
$user->setPasswordRequestedAt(new \DateTime());
$entityManager->persist($user);
$entityManager->flush();
$url = $this->container->get('router')->generate(
'app_reset_password',
[
'confirmationToken' => $user->getConfirmationToken(),
],
UrlGeneratorInterface::NETWORK_PATH
);
$options = [
'resetPasswordUrl' => $url,
'siteName' => $siteParamsHelper->getSiteName(),
'siteUrl' => $siteParamsHelper->getSiteUrl(),
'address' => $siteParamsHelper->getSiteAddress(),
MailTemplateProvider::CODE => $forgotPasswordTemplateConfig->getValue()
];
$email = (new TemplatedEmail())
->from(new Address($siteParamsHelper->getNoReplyEmail(), $siteParamsHelper->getSiteName()))
->to($user->getEmail())
->subject($translator->trans('Reset Your Password'))
->html($mailTemplateProvider->get($options));
$mailer->send($email);
return $this->render('@KobizoCore/frontend/password-sent.twig', [
'email' => $user->getEmail(),
]);
}
}
return $this->render('@KobizoCore/frontend/request-password.twig', [
'requestPasswordForm' => $form->createView(),
]);
}
/**
* @Route("/reset/{confirmationToken}", name="app_reset_password")
*/
public function reset(
Request $request,
UserRepository $repository,
UserAuthenticatorInterface $userAuthenticator,
LoginFormAuthenticator $authenticator,
UserPasswordHasherInterface $userPasswordHasher,
EntityManagerInterface $entityManager,
AdminUrlConfig $adminUrlConfig,
string $confirmationToken
): Response {
if ($this->isGranted(AuthenticatedVoter::IS_AUTHENTICATED_FULLY)) {
return $this->redirectToRoute('dashboard_analytics');
}
$form = $this->createForm(ResetPasswordFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $repository->findOneByConfirmationToken($form->get('confirmationToken')->getData());
if (null === $user || !$user->isPasswordRequestNoneExpired(self::TTL_RESET_TIME)) {
return new RedirectResponse($this->container->get('router')->generate('app_request_password'));
}
$user->setPassword(
$userPasswordHasher->hashPassword(
$user,
$form->get('plainPassword')->getData()
)
);
$user->setConfirmationToken(null);
$user->setPasswordRequestedAt(null);
$entityManager->persist($user);
$entityManager->flush();
$userAuthenticator->authenticateUser(
$user,
$authenticator,
$request,
);
if ($this->isGranted(DashboardResource::DASHBOARD_CRM) && $user->isAdmin()) {
return $this->redirectToRoute('dashboard_analytics', ['admin' => $adminUrlConfig->getValue()]);
}
if ($this->isGranted(DefaultRolesAttribute::CLIENT)) {
return $this->redirectToRoute('customer_account');
}
return $this->redirectToRoute('home');
}
return $this->render('@KobizoCore/frontend/reset-password.twig', [
'resetPasswordForm' => $form->createView(),
'confirmationToken' => $confirmationToken,
]);
}
}