src/Controller/SecurityController.php line 100

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\ResetPassword;
  4. use App\Entity\Users;
  5. use App\Entity\UserAdditionalDetails;
  6. use App\Entity\ProfileClassification;
  7. use App\Entity\UsersCategories;
  8. use App\Entity\VehicleClients;
  9. use App\Form\ResetPasswordType;
  10. use App\Form\UserRegistrationType;
  11. use Gregwar\Captcha\CaptchaBuilder;
  12. use Gregwar\Captcha\PhraseBuilder;
  13. use Psr\Log\LoggerInterface;
  14. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
  15. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  16. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  17. use Symfony\Component\HttpFoundation\Response;
  18. use Symfony\Component\HttpFoundation\JsonResponse;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  21. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  22. use Unirest;
  23. use Symfony\Component\Form\FormError;
  24. use App\Service\SMSHelper;
  25. use Symfony\Component\Security\Core\Security;
  26. use Symfony\Contracts\Translation\TranslatorInterface;
  27. /**
  28.  * Class SecurityController
  29.  * @package App\Controller
  30.  */
  31. class SecurityController extends AbstractController
  32. {
  33.     /**
  34.      * @param Request $request
  35.      * @param AuthenticationUtils $authenticationUtils
  36.      *
  37.      * @Route("/login", name="login")
  38.      *
  39.      * @return \Symfony\Component\HttpFoundation\Response
  40.      */
  41.     public function loginAction(Security $securityAuthenticationUtils $authenticationUtils): Response
  42.     {
  43.         // redirect to profile if user logged 
  44.         if($security->getUser()){
  45.             return $this->redirectToRoute('my_profile');
  46.         }
  47.         $error        $authenticationUtils->getLastAuthenticationError();
  48.         $lastUsername $authenticationUtils->getLastUsername();
  49.         return $this->render('security/login.html.twig', array(
  50.             'last_username' => $lastUsername,
  51.             'error'         => $error
  52.         ));
  53.     }
  54.     /**
  55.      * @Route("/logout", name="logout")
  56.      *
  57.      * @throws \Exception
  58.      */
  59.     public function logoutAction()
  60.     {
  61.         throw new \Exception('This should never be reached!');
  62.     }
  63.     /**
  64.      * @param Request $request
  65.      * @param UserPasswordEncoderInterface $passwordEncoder
  66.      *
  67.      * @Route("/reg/getCaptcha", name="get_captcha_ajax")
  68.      * @Method("POST")
  69.      *
  70.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
  71.      * @throws Unirest\Exception
  72.      */
  73.     public function regenerateCaptchaAjaxAction(Request $request)
  74.     {
  75.         if ($request->isXMLHttpRequest()) {
  76.             $session   $request->getSession();
  77.             $builder $this->createCaptcha($session);
  78.             return new JsonResponse(['builder' => $builder->inline()]);
  79.         }
  80.     }
  81.     /**
  82.      * @param Request $request
  83.      * @param UserPasswordEncoderInterface $passwordEncoder
  84.      *
  85.      * @Route("/register", name="user_registration")
  86.      * @Route("/reg", name="user_reg")
  87.      * @Method({"GET","POST"})
  88.      *
  89.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
  90.      * @throws Unirest\Exception
  91.      */
  92.     public function registerAction(Request $requestUserPasswordEncoderInterface $passwordEncoderLoggerInterface $loggerTranslatorInterface $translator)
  93.     {
  94.         // redirect to profile if user logged
  95.         if($this->getUser()){
  96.             return $this->redirectToRoute('my_profile');
  97.         }
  98.         $session   $request->getSession();
  99.         $locale    $request->getLocale();
  100.         $errorCaptcha false;
  101.         // 1) build the form
  102.         $user = new Users();
  103.         $form $this->createForm(UserRegistrationType::class, $user, ['locale' => $locale]);
  104.         // 2) handle the submit (will only happen on POST)
  105.         $form->handleRequest($request);
  106.         if ($form->isSubmitted() && $form->isValid()) {
  107.             // refresh CSRF token (form_intention)
  108.             $this->get("security.csrf.token_manager")->refreshToken("form_intention");
  109.             $postedData  $request->request->all();
  110.             $code        $postedData['sms_code'];
  111.             $userCaptcha $postedData['userCaptcha'];
  112.             if ($userCaptcha == $session->get('captchaPhrase')) {
  113.                 if ($code == $session->get('verificationCode')) {
  114.                     $password     rand(10019998);
  115.                     $mobileNumber $user->getMobileNumber();
  116.                     preg_match('/^(?:0|966)*(5[0-9]{8})$/'$mobileNumber$mobNumChunks);
  117.                     $user->setMobileNumber($mobNumChunks[1]); //remove leading zero or KSA country code if any exists
  118.                     $username $user->getUserIdentityInfo()->getIdentificationNumber();
  119.                     // 3) Encode the password (you could also do this via Doctrine listener)
  120.                     $hashedPassword $passwordEncoder->encodePassword($user$password);
  121.                     $user->setPassword($hashedPassword);
  122.                     // 4) save the User!
  123.                     $em       $this->getDoctrine()->getManager();
  124.                     $category $em->getRepository(UsersCategories::class)->find(1);
  125.                     $userIdentityInfo $user->getUserIdentityInfo();
  126.                     $user->setUserIdentityInfo(null);
  127.                     $user->setCategory($category);
  128.                     $user->setIsReceiveSms(true); //the self-registered users by default accept to receive our SMS
  129.                     $user->setUsername($userIdentityInfo->getIdentificationNumber());
  130.                     $user->setProfileOrigin("self registered");
  131.                     $em->persist($user);
  132.                     //if image uploading is required, so this is the place where to add upload code
  133.                     $em->flush($user);
  134.                     // saving user identity info
  135.                     $user->setUserIdentityInfo($userIdentityInfo);
  136.                     $userIdentityInfo->setUser($user);
  137.                     $userAdditionalDetails = new UserAdditionalDetails();
  138.                     $registeredClassification $em->getRepository(ProfileClassification::class)->findBy(['nameEn'=> 'Registered']);
  139.                     $userAdditionalDetails->setClassification($registeredClassification[0]);
  140.                     $userAdditionalDetails->setUser($user);
  141.                     $user->setUserAdditionalDetails($userAdditionalDetails);
  142.                     $em->persist($userAdditionalDetails);
  143.                     $em->flush($userAdditionalDetails);
  144.                     // Create vehicle client account
  145.                     $vehicleClient = new VehicleClients();
  146.                     $vehicleClient->setUser($user);
  147.                     $vehicleClient->setClientId($user->getUserId());
  148.                     $vehicleClient->setIsActive(1);
  149.                     $em->persist($vehicleClient);
  150.                     $em->persist($userIdentityInfo);
  151.                     $em->flush();
  152.                     
  153.                     $message $translator->trans('your login info ID and password are',
  154.                             ['%{username}'=> $username'%{password}'=> $password'%{newline}'=> "\n"], 'clients');
  155.                     if ($this->sendSMSToUser($message$mobileNumber'randum generated password'$logger)) {
  156.                         return $this->redirectToRoute('user_thanking');
  157.                     } else {
  158.                         // password did not sent to customer
  159.                         $session->getFlashBag()->add('info',
  160.                             $translator->trans('no password sent', array(), 'clients')
  161.                         );
  162.                         $logger->info('Register Action: no password sent to mobile num: '$user->getMobileNumber());
  163.                         return $this->redirectToRoute('login');
  164.                     }
  165.                 } else {
  166.                     // activation code is wrong
  167.                     $errorMessage $translator->trans('you have entered a wrong verification code please enter the correct one', array(''), 'validators');
  168.                     $form->addError(new FormError($errorMessage)); //this is how to add an error to Symfony form
  169.                     $logger->info('Register Action: you have entered a wrong verification code please enter the correct one, mobile num is '$user->getMobileNumber());
  170.                 }
  171.             } else {
  172.                 // captcha code is wrong
  173.                 $errorMessage $translator->trans('captcha code is wrong', array(''), 'validators');
  174.                 $form->addError(new FormError($errorMessage)); //this is how to add an error to Symfony form
  175.                 $logger->info('Register Action: you have entered a wrong captcha code, mobile num is '$user->getMobileNumber());
  176.                 $errorCaptcha $translator->trans('captcha code is wrong', array(''), 'validators');
  177.             }
  178.         }
  179.         $builder $this->createCaptcha($session);
  180.         return $this->render('security/register.html.twig', array(
  181.             'form'      => $form->createView(),
  182.             'locale'    => $locale,
  183.             'builder'   => $builder,
  184.             'errorCaptcha'   => $errorCaptcha,
  185.         ));
  186.     }
  187.     /**
  188.      * @param Request $request
  189.      *
  190.      * @Route("forgotPassword", name="forgot_password")
  191.      * @Route("/getCaptchaForgot", name="get_captcha_forgot_ajax")
  192.      * @Method({"GET", "POST"})
  193.      *
  194.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
  195.      * @throws Unirest\Exception
  196.      */
  197.     public function forgotPasswordAction(Request $requestLoggerInterface $loggerTranslatorInterface $translator)
  198.     {
  199.         $session $request->getSession();
  200.         //for ajax request
  201.         if ($request->isXMLHttpRequest()) {
  202.             $builder      $this->createCaptcha($session);
  203.             return new JsonResponse(['builder' => $builder->inline()]);
  204.         }
  205.         if ($request->isMethod('post')) {
  206.             //if post, validate then send verification code
  207.             $postedData   $request->request->all();
  208.             $userCaptcha  $postedData['userCaptcha'];
  209.             $mobileNumber $postedData['mobileNumber'];
  210.             // if the mobile number starts 0 , remove it
  211.              if(substr($mobileNumber,0,1) == 0){
  212.                 $mobileNumber =  substr($mobileNumber,1);
  213.             }
  214.             if ($userCaptcha == $session->get('captchaPhrase')) {
  215.                 $em   $this->getDoctrine()->getManager();
  216.                 $user $em->getRepository(Users::class)->findOneBy(['mobileNumber' => $mobileNumber]);
  217.                 if ($user) {
  218.                     $code rand(101998);
  219.                     $session->set('activationCode'$code);
  220.                     
  221.                     $message $translator->trans('to reset your password enter this code', array(), 'clients') . ': '$code.
  222.                         "\n" $translator->trans('your ID is', [], 'clients') . ': ' $user->getUsername();
  223.                     if ($this->sendSMSToUser($message$mobileNumber'forgot password code'$logger)) {
  224.                         $session->set('mobileNumber'$mobileNumber);
  225.                         return $this->redirectToRoute('reset_password');
  226.                     } else {
  227.                         // code did not sent to customer
  228.                         $session->getFlashBag()->add('info',
  229.                             $translator->trans('no code sent', array(), 'clients')
  230.                         );
  231.                         return $this->redirectToRoute('forgot_password');
  232.                     }
  233.                 } else {
  234.                     // no user registered with this mobile number
  235.                     $errorCode $translator->trans('no user registered by this mobile number', array(''), 'validators');
  236.                     $builder   $this->createCaptcha($session);
  237.                 }
  238.             } else {
  239.                 // captcha code is wrong
  240.                 $errorCode $translator->trans('you have enterd a wrong captcha code', array(''), 'validators');
  241.                 $builder   $this->createCaptcha($session);
  242.             }
  243.         } else {
  244.             $builder      $this->createCaptcha($session);
  245.             $errorCode    null;
  246.             $mobileNumber '';
  247.         }
  248.         return $this->render('security/forgot_password.html.twig'compact('builder''errorCode''mobileNumber'));
  249.     }
  250.     /**
  251.      * @param Request $request
  252.      * @param UserPasswordEncoderInterface $passwordEncoder
  253.      * @param $mobileNumber
  254.      *
  255.      * @Route("/resetPassword", name="reset_password")
  256.      * @Method({"GET", "POST"})
  257.      *
  258.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
  259.      */
  260.     public function resetPasswordAction(Request $requestUserPasswordEncoderInterface $passwordEncoderTranslatorInterface $translator)
  261.     {
  262.         $session       $request->getSession();
  263.         $resetPassword = new ResetPassword();
  264.         $errorCode     '';
  265.         $mobileNumber$session->get('mobileNumber');
  266.         $form $this->createForm(ResetPasswordType::class, $resetPassword, ['capital' => false]);
  267.         $form->handleRequest($request);
  268.         if ($form->isSubmitted() && $form->isValid()) {
  269.             $em   $this->getDoctrine()->getManager();
  270.             $user $em->getRepository(Users::class)->findOneBy(['mobileNumber' => $mobileNumber]);
  271.             if ($user) {
  272.                 $code $resetPassword->getSmsCode();
  273.                 if ($code == $session->get('activationCode')) {
  274.                     $newPassword    $resetPassword->getNewPassword();
  275.                     //$user           = $this->getUser();
  276.                     $hashedPassword $passwordEncoder->encodePassword($user$newPassword);
  277.                     $user->setPassword($hashedPassword);
  278.                     $em->flush($user);
  279.                     $session->getFlashBag()->add('success',
  280.                         $translator->trans('password changed successfully', array(), 'clients')
  281.                     );
  282.                     return $this->redirectToRoute('login');
  283.                 } else {
  284.                     // activation code is wrong
  285.                     $errorCode $translator->trans('you have entered a wrong activation code please enter the correct one', array(''), 'validators');
  286.                 }
  287.             } else {
  288.                 // no user registered by his mobile number
  289.                 $errorCode $translator->trans('no user registered by this mobile number', array(''), 'validators');
  290.                 $builder   $this->createCaptcha($session);
  291.             }
  292.         }
  293.         return $this->render('security/reset_password.html.twig', array(
  294.             'form'      => $form->createView(),
  295.             'errorCode' => $errorCode
  296.         ));
  297.     }
  298.     /**
  299.      * @param $passwordOrCode
  300.      * @param $mobileNumber
  301.      * @param $smsType
  302.      * @param null $username
  303.      *
  304.      * @return bool
  305.      * @throws Unirest\Exception
  306.      */
  307.     private function sendSMSToUser($message$mobileNumber$smsTypeLoggerInterface $logger)
  308.     {
  309.         if ( !preg_match('/^(?:0|966)*(5[0-9]{8})$/'$mobileNumber$mobNumChunks) ) {
  310.             $logger->info"Unable to send $smsType SMS due to wrong mobile num :"$mobileNumber);
  311.             return false;
  312.         }
  313.         $mobileNumber '966'$mobNumChunks[1]; //add KSA country code
  314.         //send the code into an SMS
  315.         $smsHelper =   new  SMSHelper();
  316.         $sendStatus$smsHelper->sendSms$message $mobileNumber);
  317.         $logger->info(\Doctrine\Common\Util\Debug::dump($smsHelper->getRawResponse(), 2truefalse));
  318.         switch ($sendStatus){
  319.             case $smsHelper::STATUS['sms_seems_sent'];
  320.                 $logger->info"sending $smsType SMS to mobile num :"$mobileNumber" sent!");
  321.                 return true;
  322.                 break;
  323.             case $smsHelper::STATUS['sms_send_failed'];
  324.             case $smsHelper::STATUS['request_failed'];
  325.                 $logger->info"Failed sending $smsType SMS to mobile num :"$mobileNumber" due to this exception: "$smsHelper->getException());
  326.                 return false;
  327.                 break;
  328.         }
  329.             
  330.     }
  331.     /**
  332.      * @return CaptchaBuilder
  333.      */
  334.     private function createCaptcha($session)
  335.     {
  336.         // Will build phrases of 4 characters, only digits
  337.         $phraseBuilder = new PhraseBuilder(4'0123456789');
  338.         $builder       = new CaptchaBuilder(null$phraseBuilder);
  339.         $builder->build(11550);
  340.         $session->set('captchaPhrase'$builder->getPhrase());
  341.         return $builder;
  342.     }
  343. }