<?php
declare(strict_types=1);
namespace App\Bundles\UserBundle\Controller;
use App\Bundles\UserBundle\DTO\ChangePasswordDTO;
use App\Bundles\UserBundle\DTO\ForgotPasswordDTO;
use App\Bundles\UserBundle\Entity\UserInterface;
use App\Bundles\UserBundle\Exception\PasswordAlreadyUsedException;
use App\Bundles\UserBundle\Exception\PasswordValidationException;
use App\Bundles\UserBundle\Exception\UserNotFoundException;
use App\Bundles\UserBundle\Form\Type\UserPassword\ChangePasswordForm;
use App\Bundles\UserBundle\Form\Type\UserPassword\ForgotPasswordType;
use App\Bundles\UserBundle\Service\User\UserProvider;
use App\Bundles\UserBundle\Service\UserEmail\UserEmailSender;
use App\Bundles\UserBundle\Service\UserPassword\ForgottenPasswordService;
use App\Bundles\UserBundle\Service\UserPassword\UserPasswordService;
use App\Platform\Service\SessionProvider;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
class PasswordController extends AbstractController
{
public function __construct(
private readonly UserEmailSender $userEmailSender,
private readonly UserProvider $provider,
private readonly UserPasswordService $service,
private readonly TranslatorInterface $translator,
private readonly ForgottenPasswordService $passwordService,
private readonly SessionProvider $sessionProvider,
) {
}
#[Route(path: '/password', name: 'app_password', methods: ['GET', 'POST'])]
public function changePassword(Request $request): Response
{
$form = $this->createForm(ChangePasswordForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var UserInterface $user */
$user = $this->getUser();
/** @var ChangePasswordDTO $dto */
$dto = $form->getData();
try {
$this->service->setNewPasswordForUser($user, $dto);
} catch (PasswordAlreadyUsedException | PasswordValidationException $ex) {
$this->addFlash('error', $this->translator->trans($ex->getMessage(), [], 'UserBundle'));
}
return $this->redirectToRoute('users.index');
}
return $this->renderForm('@User/password/change_password_form.html.twig', compact('form'));
}
#[Route(path: '/password/user', name: 'app_request_change_password', methods: ['POST'])]
public function sendRequestForUser(Request $request): Response
{
$user = $this->provider->provide((int) $request->get('id'));
$this->userEmailSender->sendEmailWithRequestForChangePassword(
$user,
'email_reset_password_by_admin',
$this->translator->trans(id: 'email.subject.email_reset_password_by_admin', domain: 'UserBundle')
);
return $this->redirectToRoute('users.show', ['id' => $user->getId()]);
}
#[Route(path: '/password/forgot', name: 'app_forgot_password', methods: ['GET', 'POST'])]
public function forgotPassword(Request $request): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('app.home');
}
$form = $this->createForm(ForgotPasswordType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var ForgotPasswordDTO $formData */
$formData = $form->getData();
try {
$this->passwordService->restorePassword($formData);
} catch (UserNotFoundException) {
$this->addFlash(
'error',
$this->translator->trans(id: 'auth.password_restored.bad_credentials', domain: 'UserBundle')
);
return $this->redirectToRoute('app_forgot_password');
}
$this->addFlash('sended_email', $formData->getEmail());
return $this->redirectToRoute('app_forgot_password_success');
}
return $this->renderForm('@User/password/forgot_password_form.html.twig', compact('form'));
}
#[Route(path: '/password/forgot/success', name: 'app_forgot_password_success', methods: ['GET', 'POST'])]
public function forgotPasswordEmailSuccess(Request $request): Response
{
/** @var Session $session */
$session = $this->sessionProvider->provide();
$bag = $session->getFlashBag()->get('sended_email');
if (empty($bag)) {
return $this->redirectToRoute('app_login');
}
$email = $bag[0];
return $this->render('@User/password/restore_password_success.html.twig', compact('email'));
}
}