<?php
namespace App\Controller;
use App\Constant\UserStatus;
use App\Entity\User;
use App\Services\HashGenerator;
use App\Services\Mailer;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class SecurityController extends AbstractController
{
private $doctrine;
private $hashGenerator;
private $mailer;
private $passwordEncoder;
public function __construct(ManagerRegistry $doctrine, HashGenerator $hashGenerator, Mailer $mailer, UserPasswordHasherInterface $passwordEncoder){
$this->doctrine = $doctrine;
$this->hashGenerator = $hashGenerator;
$this->mailer = $mailer;
$this->passwordEncoder = $passwordEncoder;
}
/**
* @Route("/", name="login")
*/
public function login(AuthenticationUtils $authenticationUtils)
{
// redirect if already logged
if ($this->getUser()) {
$userRoles = $this->getUser()->getRoles();
if (in_array("ROLE_SUPER_ADMIN", $userRoles) || in_array("ROLE_ADMIN", $userRoles)){
return $this->redirectToRoute('admin_dashboard');
}
if (in_array("ROLE_PARTNER", $userRoles)){
return $this->redirectToRoute('partner_dashboard');
}
if (in_array("ROLE_CUSTOMER", $userRoles)){
return $this->redirectToRoute('account_projects', ['accountId' => $this->getUser()->getMembership()->getAccount()->getId()]);
}
}
$error = $authenticationUtils->getLastAuthenticationError();
$lastEmail = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', [
'title' => "Log in",
'last_email' => $lastEmail,
'error' => $error,
'type' => 'admin'
]);
}
/**
* @Route("/logout", name="logout")
*/
public function logout()
{
}
/**
* @Route("/access-denied", name="access_denied")
*/
public function accessDenied(): Response {
return $this->render('security/access-denied.html.twig');
}
/**
* @Route("/forgot-password", name="forgot_password")
*/
public function forgotPassword(): Response {
$error = '';
$message = '';
$email = '';
if ($_POST) {
$email = $_POST['email'];
$repository = $this->doctrine->getRepository(User::class);
$user = $repository->findOneBy(['email' => $_POST['email']]);
if ($user){
$userStatus = new UserStatus();
$statusSuspended = $userStatus->getUserStatusId('Suspended');
if ($user->getStatus() == $statusSuspended) {
$error = 'Your user account has been suspended.';
} else {
$lastTokenCreated = $user->getTokenCreatedAt();
$dateValid = (new \DateTime("now"))->modify('-1 hour');
if ($lastTokenCreated && $lastTokenCreated > $dateValid){
$error = 'We already received your request. Check your email or try again later.';
} else {
$token = $this->hashGenerator->uuid4();
$user->setToken($token);
$user->setTokenCreatedAt(new \DateTime());
$em = $this->doctrine->getManager();
$em->persist($user);
$em->flush();
$url = $this->generateUrl('reset_password',
array('token' => $token),
UrlGeneratorInterface::ABSOLUTE_URL
);
$context = [
'user_email' => $user->getEmail(),
'url' => $url
];
$to = $user->getEmail();
$subject = 'Reset Your Password.';
$type = 'reset_password';
$this->mailer->sendTemplatedMail($to, $subject, $type, $context);
$message = 'Request for password reset sent successfully. Check your email for further instructions.';
$email = '';
}
}
} else {
$error = 'User not found';
}
}
return $this->render('security/forgot-password.html.twig', [
'title' => "Forgot password",
'last_email' => $email,
'error' => $error,
'message' => $message
]);
}
/**
* @Route("/reset-password/{token}", name="reset_password")
*/
public function resetPassword($token)
{
$error = '';
$message = '';
$repository = $this->doctrine->getRepository(User::class);
$user = $repository->findOneBy(['token' => $token]);
$userStatus = new UserStatus();
$statusSuspended = $userStatus->getUserStatusId('Suspended');
if (!$user) {
$error = 'Your request has been expired.';
} else if ($user->getStatus() == $statusSuspended) {
$error = 'Your user account has been suspended.';
} else if ($_POST) {
$password = trim($_POST['password']);
$password_retype = trim($_POST['password_retype']);
$strength = $this->hashGenerator->passwordStrengthCheck($password);
if(!$strength['valid']) {
$error = $strength['message'];
} else if ($password != $password_retype){
$error = "Retyped password doesn't match";
} else {
$new_pwd_encoded = $this->passwordEncoder->hashPassword($user, $password);
$currentStatus = $user->getStatus();
$statusPending = $userStatus->getUserStatusId('Pending');
$statusActive = $userStatus->getUserStatusId('Active');
if ($currentStatus == $statusPending){
$user->setStatus($statusActive);
}
$user->setToken(null);
$user->setTokenCreatedAt(null);
$user->setPassword($new_pwd_encoded);
$em = $this->doctrine->getManager();
$em->persist($user);
$em->flush();
$this->addFlash(
'notice',
'Your password has been changed.'
);
return $this->redirectToRoute('login');
}
}
return $this->render('security/reset-password.html.twig', [
'title' => "Reset password",
'token' => $token,
'error' => $error,
'message' => $message
]);
}
/**
* @Route("/my-profile", name="my_profile")
*/
public function myProfile(Request $request): Response {
$error = false;
$passChanged = false;
$message = '';
if ($request->isMethod('post')) {
$user = $this->getUser();
$firstName = trim($request->get('firstName'));
$lastName = trim($request->get('lastName'));
$password = trim($request->get('password'));
$password_retype = trim($request->get('password_retype'));
$infoChanged = ($firstName != $user->getFirstName() || $lastName != $user->getLastName());
if (strlen($firstName) < 2 || strlen($lastName) < 2) {
$error = true;
$message .= 'Your first name and last name should be at least 2 characters long<br>';
} else {
$user->setFirstName($firstName);
$user->setlastName($lastName);
}
if (strlen($password) > 0){
$strength = $this->hashGenerator->passwordStrengthCheck($password);
if(!$strength['valid']) {
$error = true;
$message .= $strength['message'].'<br>';
} else if ($password != $password_retype){
$error = true;
$message .= "Retyped password doesn't match<br>";
} else {
$new_pwd_encoded = $this->passwordEncoder->hashPassword($user, $password);
$user->setPassword($new_pwd_encoded);
$passChanged = true;
}
}
if ($error){
$this->addFlash('error', $message);
} else {
$em = $this->doctrine->getManager();
$em->persist($user);
$em->flush();
if ($infoChanged && $passChanged){
$this->addFlash('notice', 'Your profile info and password successfully changed');
} elseif ($infoChanged) {
$this->addFlash('notice', 'Your profile info successfully changed');
} elseif ($passChanged){
$this->addFlash('notice', 'Your password successfully changed');
} else {
$this->addFlash('notice', 'Nothing changed');
}
}
}
$appType = '';
$account = null;
$roles = $this->getUser()->getRoles();
foreach ($roles as $role){
if ($role == "ROLE_ADMIN" || $role == "ROLE_SUPER_ADMIN" || $role == "ROLE_ADMIN_VIEWER"){
$appType = 'admin';
}
if ($role == "ROLE_PARTNER"){
$appType = 'partner';
}
if ($role == "ROLE_CUSTOMER"){
$appType = 'account';
$account = $this->getUser()->getMembership()->getAccount();
}
}
return $this->render('security/profile.html.twig', [
'app_type' => $appType,
'title' => 'My Profile',
'account' => $account,
'accountId' => ($account) ? $account->getId() : null,
'showPayment' => false,
]);
}
}