<?php
/**
* User controller class
*
* PHP version 7.4
*
* @category App
* @package App\Controller
* @author Momcilo Radotic <m.radotic@outlook.com>
* @copyright 2021 MoravaPro
* @license MoravaPro
*/
namespace App\Controller;
use App\Entity\Organization;
use App\Entity\User;
use App\Entity\UserStatus;
use App\Helper\UserUtils;
use App\Validation\Form\ChangePasswordForm;
use App\Validation\Form\LoginForm;
use App\Validation\Form\LostPasswordForm;
use App\Validation\Form\UserConfirmationForm;
use FOS\RestBundle\Controller\Annotations as Rest;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* User controller class
*
* @category App
* @package App\Controller
*/
class UserController extends BaseController
{
/**
* Login action
*
* @Rest\Post("/login", name="user_login_post")
* @Rest\Get("/login", name="user_login_get")
*
* @return Response
*/
public function loginAction() : Response
{
/** @var User $user */
$user = $this->getUser();
if ($user) {
$page = $user->getOrganization()->getStatus() == Organization::REGISTERED ? 'complete-registration' : 'dashboard';
return $this->redirectToRoute(
'index_application', ['page' => $page]
);
}
$loginForm = new LoginForm();
$formBuilder = $this->createFormBuilder($loginForm);
$form = $formBuilder->add('username', TextType::class)
->add('password', PasswordType::class)
->getForm();
return $this->render('view/login.html.twig', array('form' => $form->createView(), 'message' => '', 'language' => 'en'));
}
/**
* Action for rendering lost password form
*
* @Rest\Get("/lost-password", name="user_lost_password_get")
* @Rest\Post("/lost-password", name="user_lost_password_post")
*
* @param Request $request
* @param UserUtils $userUtils
*
* @return Response
*/
public function lostPasswordAction(Request $request, UserUtils $userUtils) : Response
{
$lostPasswordForm = new LostPasswordForm();
$formBuilder = $this->createFormBuilder($lostPasswordForm);
$form = $formBuilder->add('email', EmailType::class)->getForm();
$form->handleRequest($request);
$errorMessage = null;
if ($form->isSubmitted() && $form->isValid()) {
$user = $this->getDoctrine()->getManager()->getRepository(User::class)->findOneBy(array('email' => strtolower($lostPasswordForm->getEmail())));
if (isset($user)) {
$changePasswordKey = $userUtils->generateUserHash($lostPasswordForm->getEmail() . time());
$user->setPasswordKey($changePasswordKey);
$ttl = time() + $this->getParameter('change_password_ttl');
$user->setPasswordKeyTtl((new \DateTime())->setTimestamp($ttl));
$this->getDoctrine()->getManager()->flush();
$result = $this->mailer->sendSystemMail(
$this->translator->trans('Password recovery'),
$lostPasswordForm->getEmail(),
$this->renderView(
'view/email/lost-password.html.twig',
array(
'subject' => $this->translator->trans('Password recovery'),
'content'=> $this->utils->getBaseUrl() . '/change-password/?active_key=' . $changePasswordKey,
'base_url' => $this->utils->getBaseUrl()
)
)
);
if ($result > 0) {
return $this->redirectToRoute('user_reset_password_email_sent');
} else {
$errorMessage = $this->translator->trans('Failed to send email to email address');
}
} else {
$this->logger->info($this->translator->trans("No user found")." ".$lostPasswordForm->getEmail());
$errorMessage = $this->translator->trans('Invalid email');
}
}
return $this->render(
'view/lost-password.html.twig',
array(
'form' => $form->createView(),
'error_message' => $errorMessage
)
);
}
/**
* Action for rendering change password form
*
* @Rest\Get("/change-password", name="user_change_password_get")
* @Rest\Post("/change-password", name="user_change_password_post")
*
* @param Request $request
* @param UserUtils $userUtils
*
* @return Response
*/
public function changePasswordAction(Request $request, UserUtils $userUtils) : Response
{
$changePasswordForm = new ChangePasswordForm();
$formBuilder = $this->createFormBuilder($changePasswordForm);
$passwordKey = $request->query->get('active_key');
$user = $this->getDoctrine()->getManager()->getRepository(User::class)
->findOneBy(['password_key' => $passwordKey]);
if (!$user || $user->getPasswordKeyTtl() < new \DateTime()) {
if ($user) {
$user->setPasswordKey(null);
$user->setPasswordKeyTtl(null);
$this->getDoctrine()->getManager()->flush();
}
$errorMessage = $user ? 'Change password key has expired.' : 'Invalid request';
return $this->render(
'view/error-400.html.twig',
['error_message' => $errorMessage]
);
}
$form = $formBuilder->add('active_key', HiddenType::class, array('attr' => array('value' => $passwordKey)))
->add('password', RepeatedType::class,
array(
'type' => PasswordType::class,
'invalid_message' => 'The password fields must match',
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
)
)->getForm();
$form->handleRequest($request);
$errorMessage = null;
if ($form->isSubmitted() && $form->isValid()) {
$password = $userUtils->generatePassword($user, $changePasswordForm->getPassword());
$user->setPassword($password);
$user->setModified(new \DateTime());
$this->getDoctrine()->getManager()->flush();
$content = "Your password is changed, click on this link to recover ...";
$this->mailer->sendSystemMail(
$this->translator->trans('Change password'),
$user->getEmail(),
$this->renderView(
'view/email/changed-password.html.twig',
array(
'subject' => $this->translator->trans('Password changed'),
'content'=>$content,
'base_url' => $this->utils->getBaseUrl()
)
),
);
return $this->redirectToRoute('user_password_changed');
}
return $this->render(
'view/change-password.html.twig',
array('form' => $form->createView(),
'error_message' => $errorMessage,
)
);
}
/**
* User confirmation
*
* @Rest\Get("/user/confirm", name="user_confirm" )
* @Rest\Post("/user/confirm", name="user_confirm_post" )
*
* @param Request $request
* @param UserUtils $userUtils
*
* @return Response
*/
public function inviteConfirmAction(Request $request, UserUtils $userUtils) : Response
{
$activeKey = $request->query->get('active_key');
$user = $this->getDoctrine()->getManager()->getRepository(User::class)
->findOneBy(array('activation_key' => $activeKey, 'status' => UserStatus::REGISTERED));
if (isset($user)) {
$userConfirmationForm = new UserConfirmationForm();
$userConfirmationForm->setEmail($user->getEmail());
$userConfirmationForm->setFirstName($user->getFirstName());
$userConfirmationForm->setLastName($user->getLastName());
$formGenerator = function() use ($userConfirmationForm, $user) {
$formBuilder = $this->createFormBuilder($userConfirmationForm);
return $formBuilder->add(
'password',
RepeatedType::class,
array(
'type' => PasswordType::class,
'invalid_message' => $this->translator->trans('The password fields must match'),
'first_options' => array('label' => $this->translator->trans('Password')),
'second_options' => array('label' => $this->translator->trans('Repeat Password')),
)
)->add('email', EmailType::class, ['attr'=> [ 'readonly' => true, 'disabled' => true]])
->add('first_name', TextType::class)
->add('last_name', TextType::class)
->getForm();
};
$errorMessage = null;
$form = $formGenerator();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user->setPassword($userUtils->generatePassword($user, $userConfirmationForm->getPassword()));
$user->setModified(new \DateTime());
$user->setFirstName($userConfirmationForm->getFirstName());
$user->setLastName($userConfirmationForm->getLastName());
$user->setStatus($this->getDoctrine()->getManager()->getRepository(UserStatus::class)->find(UserStatus::ACTIVE));
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('app_logout');
} else if ($form->isSubmitted()) {
$errorMessage = $this->translator->trans('Error during user confirmation');
$userConfirmationForm->setEmail($user->getEmail());
$form = $formGenerator();
}
return $this->render(
'view/user-confirmation.html.twig',
array(
'form' => $form->createView(),
'error_message' => $errorMessage
)
);
} else {
return $this->render(
'view/error-400.html.twig',
['error_message' => 'Invalid request']
);
}
}
/**
* Reset email sent
*
* @Rest\Get("/reset-password-email-sent", name="user_reset_password_email_sent")
*/
public function resetEmailSentAction()
{
return $this->render('view/email-sent.html.twig');
}
/**
* Password successfully changed
*
* @Rest\Get("/password-changed", name="user_password_changed")
*/
public function passwordChangedAction()
{
return $this->render('view/password-changed.html.twig');
}
}