<?php
namespace App\Controller;
use App\Entity\User;
use App\Entity\Company;
use App\Entity\PersonalInfo;
use App\Entity\Invitation;
use App\Form\RegisterCompanyType;
use App\Form\RegisterUserType;
use App\Repository\UserRepository;
use App\Service\MailgunService;
use App\Service\UtilsService;
use App\Service\LogService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class UserAuthenticationController extends AbstractController
{
// ## Basic Authentication ## //
#[Route(path: '/login', name: 'login')]
public function login(AuthenticationUtils $authenticationUtils): \Symfony\Component\HttpFoundation\Response
{
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
if ($this->getUser()) {
return $this->redirectToRoute('index');
}
return $this->render('public/user-authentication/login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error
));
}
#[Route(path: '/logged', name: 'login_check')]
public function loginCheck() : \Symfony\Component\HttpFoundation\RedirectResponse
{
$user = $this->getUser();
if (!$user) {
throw new \Exception('User not found!');
}
if(!$user->getIsActive()){
$this->addFlash(
'danger', "Your account has been disabled"
);
return $this->redirectToRoute('login');
}
if($user->getPersonalInfo() == null){
$personal_info = new PersonalInfo();
$user->setPersonalInfo($personal_info);
}
if($user->getStatus() == null){
$user->setStatus('status.off');
}
$user->setLastLoginAt(new \DateTime());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
if ($this->isGranted('ROLE_OWNER') && count($user->assignedOffices()) == 0) {
return $this->redirectToRoute('add_office');
} elseif ($user->companyOwner() && count($user->assignedCompany()->getDepartments()) == 0) {
return $this->redirectToRoute('department_settings');
} elseif($user->getPersonalInfo()->profileCompletion()['completed'] <= 1) {
return $this->redirectToRoute('edit_user_profile');
}
/*
if ($user->getLastLogin() == null) {
return $this->redirectToRoute('complete-register');
}*/
return $this->redirectToRoute('index');
}
#[Route(path: '/logout', name: 'logout', methods: ['GET'])]
public function logout()
{
// controller can be blank: it will never be executed!
throw new \Exception('Don\'t forgot to activate logout in security.yaml');
}
#[Route(path: '/forgot', name: 'forgot_password')]
public function forgotPage(Request $request, MailgunService $mailgunService, EntityManagerInterface $entityManager, UtilsService $utilsService, TranslatorInterface $translator): \Symfony\Component\HttpFoundation\Response
{
$form = $this->createFormBuilder()
->add('email', EmailType::class, array(
'label' => 'E-Mail',
'attr' => array('maxlength' => 128, 'class'=> 'form-control'),
))
->add('submit', SubmitType::class, array('label' => 'Send me reset password instructions'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && !$form->isValid()) {
foreach ($form->getErrors(true) as $error) {
$this->addFlash(
'danger', $error->getMessage()
);
}
}
if ($form->isSubmitted() && $form->isValid()) {
$email = $form["email"]->getData();
$user = $entityManager->getRepository(User::class)->findOneByEmail($email);
if ($user && $user->getIsActive()) {
$user->setForgetToken($utilsService->generateRandomString(30));
$entityManager->persist($user);
$entityManager->flush();
$confirmationUrl = $this->generateUrl('reset_password', array('forgotToken' => $user->getForgetToken()), UrlGeneratorInterface::ABSOLUTE_URL);
$mailgunService->sendEmail($translator->trans('email.password_reset'),
[$user->getEmail()],
'email/user-authentication/reset-password.html.twig',
['recipientName' => $user->getPersonalInfo()->getFirstName() ? $user->getPersonalInfo()->getFirstName() : $user->getEmail(),
'confirmationUrl' => $confirmationUrl
], false
);
}
$this->addFlash(
'success',
'We have send an email instruction to reset your password. Please check your email.'
);
}
return $this->render(
'public/user-authentication/forgot-password.html.twig',
array('form' => $form->createView())
);
}
#[Route(path: '/reset-password/{forgotToken}', name: 'reset_password')]
public function resetPassword(Request $request, EntityManagerInterface $entityManager, UtilsService $utilsService, $forgotToken, UserPasswordHasherInterface $passwordHasher)
{
$user = $entityManager->getRepository(User::class)->findOneByForgetToken($forgotToken);
if (!$user || !$user->getIsActive()) {
//throw new \Exception('User not found!');
$this->addFlash(
'warning',
'Link expired!'
);
return $this->redirectToRoute('login');
}
//$form = $this->createForm(ResetPasswordType::class);
$form = $this->createFormBuilder()
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
))
->add('submit', SubmitType::class, array('label' => 'Reset password'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user->setForgetToken(null);
$plainpassword = $form['plainPassword']->getData();
$password = $passwordHasher->hashPassword($user, $plainpassword);
$user->setPassword($password);
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash(
'success',
'Your password have been reset. Please login'
);
return $this->redirectToRoute('login');
}
return $this->render(
'public/user-authentication/reset-password.html.twig',
array('form' => $form->createView())
);
}
// ## User Registration Process ## //
#[Route(path: '/register', name: 'company_registration')]
public function companyRegistration(Request $request, UserPasswordHasherInterface $passwordHasher, MailgunService $mailgunService, UtilsService $utilsService, UserRepository $userRepository, TranslatorInterface $translator)
{
$user = new User();
$company = new Company();
$personal_info = new PersonalInfo();
$form = $this->createForm(RegisterCompanyType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && !$form->isValid()) {
foreach ($form->getErrors(true) as $error) {
$this->addFlash(
'danger', $error->getMessage()
);
}
}
if ($form->isSubmitted() && $form->isValid()) {
$lowercaseEmail = strtolower($user->getEmail());
$user->setCanonicalEmail($lowercaseEmail);
$existingUser = $userRepository->findOneByCanonicalEmail($lowercaseEmail);
if($existingUser){
$this->addFlash(
'danger', 'Email already in use, login instead'
);
return $this->redirectToRoute('login');
}
$password = $passwordHasher->hashPassword($user, $user->getPlainPassword());
$user->setPassword($password);
$user->setConfirmationToken($utilsService->generateRandomString(30));
$user->setIsActive(false);
$user->setEmailValidated(false);
$user->setRoles(array('ROLE_HR','ROLE_MANAGEMENT', 'ROLE_ACCESS_ALL_OFFICE'));
$user->setCreatedAt(new \DateTime());
$user->setPersonalInfo($personal_info);
$user->setStatus('status.off');
$company->setFullname($form->get('fullName')->getData());
$user->addCompany($company);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->persist($company);
$entityManager->flush();
$entityManager->refresh($user);
$confirmationUrl = $this->generateUrl('user_confirmation', array('confirmationToken' => $user->getConfirmationToken()), UrlGeneratorInterface::ABSOLUTE_URL);
$mailgunService->sendEmail($translator->trans('email.register_company'),
[$user->getEmail()],
'email/user-authentication/company-registration.html.twig',
['user' => $user,
'company' => $company,
'confirmationUrl' => $confirmationUrl
], false
);
$this->addFlash(
'success', "Please check your email to finish the registration process."
);
return $this->redirect($request->getUri());
/*return $this->render(
'public/user-authentication/register-form.html.twig',
array('form' => $form->createView(),
'user' => $user
)
);*/
}
return $this->render(
'public/user-authentication/register-company.html.twig',
array('form' => $form->createView())
);
}
#[Route(path: '/confirm/{confirmationToken}', name: 'user_confirmation')]
public function confirmUser($confirmationToken, EntityManagerInterface $entityManager, MailgunService $mailgunService, UserRepository $userRepository, TranslatorInterface $translator)
{
$user = $entityManager->getRepository(User::class)->findOneByConfirmationToken($confirmationToken);
$company = $user->assignedCompany();
if (!$user) {
$this->addFlash(
'warning', "User not found, please register"
);
return $this->redirectToRoute('user_registration');
//throw new NotFoundHttpException('User not found');
}
$user->setEmailValidated(true);
$user->setIsActive(true);
$entityManager->persist($user);
$entityManager->flush();
if ($user->getIsActive()) {
$mailgunService->sendEmail($translator->trans('email.registration_steps'),
[$user->getEmail()],
'email/user-authentication/company-registered.html.twig',
['user' => $user,
'company' => $company
], false
);
$this->addFlash(
'success', "Email has been verified, please login to proceed"
);
return $this->redirectToRoute('login');
} else {
return $this->render(
'public/user-authentication/register-status.html.twig',
['user' => $user]
);
}
}
#[Route(path: '/invitation', name: 'user_invitation')]
public function invitationPage(): \Symfony\Component\HttpFoundation\RedirectResponse{
//return $this->render('public/user-authentication/invitation.html.twig', []);
return $this->redirectToRoute('login');
}
#[Route(path: '/invitation/{confirmationToken}', name: 'user_invited')]
public function confirmInvitation(Request $request, $confirmationToken, EntityManagerInterface $entityManager, UserPasswordHasherInterface $passwordHasher, MailgunService $mailgunService, UserRepository $userRepository, TranslatorInterface $translator)
{
$invitation = $entityManager->getRepository(Invitation::class)->findOneByConfirmationToken($confirmationToken);
if (!$invitation) {
$this->addFlash(
'warning', "Invitation not found or expired, please register instead"
);
return $this->redirectToRoute('company_registration');
};
$user = new User();
$personal_info = new PersonalInfo();
$form = $this->createForm(RegisterUserType::class, $user);
$form->add('email', EmailType::class, array(
'label' => 'E-Mail',
'disabled' => true,
'data' => $invitation->getEmail()
));
$form->handleRequest($request);
if ($form->isSubmitted() && !$form->isValid()) {
foreach ($form->getErrors(true) as $error) {
$this->addFlash(
'danger', $error->getMessage()
);
}
}
if ($form->isSubmitted() && $form->isValid()) {
$user->setEmail($invitation->getEmail());
$user->setCanonicalEmail($invitation->getCanonicalEmail());
$existingUser = $userRepository->findOneByCanonicalEmail($invitation->getEmail());
if($existingUser){
$this->addFlash(
'danger', 'Email already in use, login instead'
);
return $this->redirectToRoute('login');
}
$invitation->setIsActive(true);
$invitation->setActivatedAt(new \DateTime());
$invitation->setConfirmationToken(null);
$password = $passwordHasher->hashPassword($user, $user->getPlainPassword());
$user->setPassword($password);
$user->setEmailValidated(true);
$user->setIsActive(true);
$user->setCreatedAt(new \DateTime());
$user->setOffice($invitation->getOffice());
$user->setPublicRoles($invitation->getRole());
$personal_info->setFirstName($form->get('firstName')->getData());
$personal_info->setMiddleName($form->get('middleName')->getData());
$personal_info->setLastName($form->get('lastName')->getData());
$user->setPersonalInfo($personal_info);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($invitation);
$entityManager->persist($user);
$entityManager->persist($personal_info);
$entityManager->flush();
$entityManager->refresh($user);
$entityManager->refresh($personal_info);
$mailgunService->sendEmail($translator->trans('email.registration_success'),
[$invitation->getEmail()],
'email/user-authentication/user-registered.html.twig',
['user' => $personal_info], false
);
$this->addFlash(
'success', "You've been registered, please login"
);
return $this->redirectToRoute('login');
}
return $this->render(
'public/user-authentication/register-user.html.twig',
['form' => $form->createView(),
'user' => $user,
'invitation' => $invitation]
);
}
// ## User Account Settings ## //
#[Route(path: '/settings/account', name: 'edit_account')]
public function editAccount(Request $request, UserPasswordHasherInterface $passwordHasher, MailgunService $mailgunService, UtilsService $utilsService, UserRepository $userRepository, LogService $log, TranslatorInterface $translator)
{
$user = $this->getUser();
$form = $this->createFormBuilder()
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array('label' => 'New password'),
'second_options' => array('label' => 'Repeat new password'),
))
->add('submit', SubmitType::class, array('label' => 'form.save'))
->getForm();
$passwordSet = $user->getPassword() ? true : false;
if($passwordSet){
$form->add('oldPassword', PasswordType::class, array(
'mapped' => false,
'label' => 'Old Password'
));
$msg_email = $translator->trans('email.password_changed');
$msg_flash = $translator->trans('messages.account.password_changed');
} else {
$msg_email = $translator->trans('email.password_set');
$msg_flash = $translator->trans('messages.account.password_set');
}
$form->handleRequest($request);
if ($form->isSubmitted() && !$form->isValid()) {
foreach ($form->getErrors(true) as $error) {
$this->addFlash(
'danger', $error->getMessage()
);
}
}
if ($form->isSubmitted() && $form->isValid()) {
if($passwordSet && !$passwordHasher->isPasswordValid($user,$form->get('oldPassword')->getData())){
$this->addFlash(
'danger', 'Old password didn\'t match!'
);
return $this->redirect($request->getUri());
}
$plainpassword = $form['plainPassword']->getData();
$password = $passwordHasher->hashPassword($user, $plainpassword);
$user->setPassword($password);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
$log->save($user, [
'owner' => $user,
'message' => 'log.password.update',
'old_data' => null,
'new_data' => null
]);
$mailgunService->sendEmail($msg_email,
[$user->getEmail()],
'email/user-notification/password-changed.html.twig',
['user' => $user], false
);
$this->addFlash('success', $msg_flash);
return $this->redirect($request->getUri());
}
return $this->render(
'private/settings/account.html.twig',[
'form' => $form->createView(),
'passwordSet' => $passwordSet
]
);
}
}