<?php declare(strict_types=1);
namespace PPAdmin\Controller;
use PlnaPenezenka\PPSDKBundle\Doctrine\Entity\Administrator;
use PlnaPenezenka\PPSDKBundle\Doctrine\Repository\AdministratorsRepository;
use PlnaPenezenka\PPSDKBundle\Service\AdministratorsManager;
use PPAdmin\EmailNotifications\AdminPasswordResetNotifier;
use PPAdmin\Form\AdminPasswordSetupForm;
use PPAdmin\Model\AdminPasswordResetException;
use PPAdmin\Security\AdminPasswordResetHandler;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Contracts\Translation\TranslatorInterface;
class SecurityController extends AbstractController
{
#[Route('/login', name: 'login', methods: ['GET', 'POST'])]
function login(AuthenticationUtils $auth_utils): Response
{
return $this->render('security/login.html.twig', [
'last_username' => $auth_utils->getLastUsername(),
'error' => $auth_utils->getLastAuthenticationError()
]);
}
#[Route('/password-reset-request', name: 'password-reset-request', methods: ['GET', 'POST'])]
function passwordResetRequest(
Request $request,
AdministratorsRepository $admin_repo,
AdminPasswordResetNotifier $password_reset_notifier,
LoggerInterface $logger,
TranslatorInterface $translator
): Response
{
$form = $this->createFormBuilder()
->add('email', EmailType::class, [
'label' => 'password-reset-request.form.email.label',
'attr' => [
'placeholder' => 'password-reset-request.form.email.placeholder'
],
'help' => 'password-reset-request.form.email.help',
'constraints' => [
new Assert\NotBlank(),
new Assert\Email(),
]
])
->add('submit', SubmitType::class, [
'label' => 'password-reset-request.form.submit.label',
'attr' => [
'class' => 'btn btn-primary btn-block'
]
])
->getForm();
$email = null;
$sent = false;
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$email = $form->get('email')->getData();
$admin = $admin_repo->findByEmail($email);
if($admin && $admin->isActivated()){
try {
$password_reset_notifier->sendPasswordSetupEmail($admin);
$sent = true;
} catch(\Exception $e){
$logger->error(__METHOD__ . ": Failed to send password reset email", [
'exception_class' => get_class($e),
'exception_message' => $e->getMessage()
]);
$form->addError(new FormError($translator->trans('password-reset-request.form.delivery-error')));
}
} else {
$sent = true;
}
}
return $this->render('security/password-reset-request.html.twig', [
'form' => $form->createView(),
'email' => $email,
'sent' => $sent
]);
}
#[Route('/password-setup/{token}', name: 'password-setup', methods: ['GET', 'POST'])]
function passwordReset(
string $token,
AdminPasswordResetHandler $reset_handler,
AdministratorsManager $admin_manager,
Request $request
): Response
{
try {
$decoded = $reset_handler->decodeToken($token);
} catch(AdminPasswordResetException $e){
throw new BadRequestHttpException($e->getMessage(), $e, $e->getCode());
}
$form = $this->createForm(AdminPasswordSetupForm::class);
$form->handleRequest($request);
$changed = false;
if($form->isSubmitted() && $form->isValid()){
$password = $form->get('new_password')->getData();
$admin_manager->changeAdminPassword($decoded->admin, $password);
$changed = true;
}
return $this->render('security/password-setup.html.twig', [
'form' => $form->createView(),
'changed' => $changed
]);
}
#[Route('/logout', name: 'logout')]
function logout()
{
throw new RuntimeException("You should not get here");
}
#[Route('/keep-alive', name: 'keep-alive')]
#[IsGranted('ROLE_ADMIN')]
function keepAlive(Request $request): JsonResponse
{
/** @var Administrator $user */
$user = $this->getUser();
$session = $request->getSession();
$session->set('keep-alive', time());
$session->getMetadataBag()->stampNew();
return $this->json([
'user_id' => $user->id,
'keep-alive' => $session->get('keep-alive')
]);
}
}