custom/plugins/LeadManager/src/Storefront/Controller/LeadManagerController.php line 365

Open in your IDE?
  1. <?php
  2. namespace Virgin\LeadManager\Storefront\Controller;
  3. use Monolog\Logger;
  4. use RuntimeException;
  5. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractSendPasswordRecoveryMailRoute;
  6. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractResetPasswordRoute;
  7. use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLogoutRoute;
  8. use Shopware\Core\Checkout\Customer\CustomerEntity;
  9. use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundByHashException;
  10. use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundException;
  11. use Shopware\Core\Checkout\Customer\Exception\CustomerRecoveryHashExpiredException;
  12. use Shopware\Core\Checkout\Customer\SalesChannel\AccountService;
  13. use Shopware\Core\Content\Category\Exception\CategoryNotFoundException;
  14. use Shopware\Core\Framework\Context;
  15. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  19. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  20. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  21. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  22. use Shopware\Core\Framework\Validation\DataValidationDefinition;
  23. use Shopware\Core\Framework\Validation\DataValidator;
  24. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  25. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextPersister;
  26. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  27. use Shopware\Core\System\SystemConfig\SystemConfigService;
  28. use Shopware\Storefront\Controller\StorefrontController;
  29. use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoader;
  30. use Shopware\Storefront\Page\Navigation\Error\ErrorPageLoader;
  31. use Symfony\Component\HttpFoundation\Cookie;
  32. use Symfony\Component\HttpFoundation\RedirectResponse;
  33. use Symfony\Component\HttpFoundation\Request;
  34. use Symfony\Component\HttpFoundation\Response;
  35. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  36. use Symfony\Component\Routing\Annotation\Route;
  37. use Symfony\Component\Validator\Constraints\Email;
  38. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  39. use Virgin\GDPRPlugin\Service\PrivacyService;
  40. use Virgin\LeadManager\Custom\Autologin\AutologinRequestDefinition;
  41. use Virgin\LeadManager\Service\AccountRegistrationServiceDecorator;
  42. use Virgin\LeadManager\Storefront\Page\Contact\ContactPageLoader;
  43. use Virgin\LeadManager\Utils\Services\LeadGenerationService;
  44. use Virgin\ProductModelExtension\Custom\Club\ClubEntity;
  45. use Virgin\ProductModelExtension\Services\ClubService;
  46. use Virgin\SubscriptionsConfigurator\Utils\Services\SubscriptionsConfiguratorService;
  47. use Virgin\SystemIntegration\Exception\VirginApiException;
  48. use Virgin\SystemIntegration\Services\RestApiClient;
  49. use Virgin\SystemIntegration\Services\VirginUser\VirginUser;
  50. use Shopware\Core\Framework\Uuid\Uuid;
  51. use DateTime;
  52. use DateTimeZone;
  53. /**
  54. * @RouteScope(scopes={"storefront"})
  55. */
  56. class LeadManagerController extends StorefrontController
  57. {
  58. const CALL = '1';
  59. const APPOINTMENT = '2';
  60. const REVOLUTION_CENTER_ID = 233;
  61. /**
  62. * @var AccountService
  63. */
  64. private $accountService;
  65. /**
  66. * @var AccountRegistrationServiceDecorator
  67. */
  68. private $accountRegistrationService;
  69. /**
  70. * @var SalesChannelContextPersister
  71. */
  72. private $contextPersister;
  73. /**
  74. * @var LeadGenerationService
  75. */
  76. private $leadService;
  77. /**
  78. * @var EntityRepository
  79. */
  80. private $customerRepository;
  81. /**
  82. * @var DataValidator
  83. */
  84. private $validator;
  85. /**
  86. * @var Logger
  87. */
  88. private $logger;
  89. /**
  90. * @var ContactPageLoader
  91. */
  92. private $contactPageLoader;
  93. /**
  94. * @var EntityRepository
  95. */
  96. private $contactRepository;
  97. /**
  98. * @var EntityRepository
  99. */
  100. private $contactTypeRepository;
  101. /**
  102. * @var EntityRepository
  103. */
  104. private $virginUserTypeRepository;
  105. /**
  106. * @var EntityRepository
  107. */
  108. private $clubRepository;
  109. /**
  110. * @var ClubService
  111. */
  112. private $clubService;
  113. /**
  114. * @var RestApiClient
  115. */
  116. private $restApiClient;
  117. /**
  118. * @var PrivacyService
  119. */
  120. private $privacyService;
  121. /**
  122. * @var SystemConfigService
  123. */
  124. private $systemConfigService;
  125. /**
  126. * @var AccountLoginPageLoader
  127. */
  128. private $loginPageLoader;
  129. /**
  130. * @var VirginUser
  131. */
  132. private $virginUser;
  133. /**
  134. * @var EventDispatcherInterface
  135. */
  136. private $eventDispatcher;
  137. /** @var SubscriptionsConfiguratorService */
  138. private $configuratorService;
  139. /**
  140. * @var EntityRepository
  141. */
  142. private $autologinRequestRepository;
  143. /**
  144. * @var ErrorPageLoader
  145. */
  146. private $errorPageLoader;
  147. /**
  148. * @var AbstractLogoutRoute
  149. */
  150. private $logoutRoute;
  151. /**
  152. * @var AbstractSendPasswordRecoveryMailRoute
  153. */
  154. private $sendPasswordRecoveryMailRoute;
  155. /**
  156. * @var AbstractResetPasswordRoute
  157. */
  158. private $resetPasswordRoute;
  159. /**
  160. * @var EntityRepository
  161. */
  162. private $customerRecoveryRepository;
  163. /**
  164. * @var SessionInterface
  165. */
  166. private $session;
  167. const TYPE_CALLCENTER = 1;
  168. const TYPE_ONSITE = 2;
  169. public function __construct(
  170. AccountService $accountService,
  171. AccountRegistrationServiceDecorator $accountRegistrationService,
  172. SalesChannelContextPersister $contextPersister,
  173. LeadGenerationService $leadService,
  174. EntityRepository $customerRepository,
  175. DataValidator $validator,
  176. Logger $logger,
  177. ContactPageLoader $contactPageLoader,
  178. EntityRepository $contactRepository,
  179. EntityRepository $contactTypeRepository,
  180. EntityRepository $virginUserTypeRepository,
  181. EntityRepository $clubRepository,
  182. ClubService $clubService,
  183. RestApiClient $restApiClient,
  184. PrivacyService $privacyService,
  185. SystemConfigService $systemConfigService,
  186. AccountLoginPageLoader $loginPageLoader,
  187. VirginUser $virginUser,
  188. EventDispatcherInterface $eventDispatcher,
  189. SubscriptionsConfiguratorService $configuratorService,
  190. EntityRepository $autologinRequestRepository,
  191. ErrorPageLoader $errorPageLoader,
  192. AbstractLogoutRoute $logoutRoute,
  193. AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute,
  194. AbstractResetPasswordRoute $resetPasswordRoute,
  195. EntityRepository $customerRecoveryRepository,
  196. SessionInterface $session
  197. )
  198. {
  199. $this->accountService = $accountService;
  200. $this->accountRegistrationService = $accountRegistrationService;
  201. $this->contextPersister = $contextPersister;
  202. $this->leadService = $leadService;
  203. $this->customerRepository = $customerRepository;
  204. $this->validator = $validator;
  205. $this->logger = $logger;
  206. $this->contactPageLoader = $contactPageLoader;
  207. $this->contactRepository = $contactRepository;
  208. $this->contactTypeRepository = $contactTypeRepository;
  209. $this->virginUserTypeRepository = $virginUserTypeRepository;
  210. $this->clubRepository = $clubRepository;
  211. $this->clubService = $clubService;
  212. $this->restApiClient = $restApiClient;
  213. $this->privacyService = $privacyService;
  214. $this->systemConfigService = $systemConfigService;
  215. $this->loginPageLoader = $loginPageLoader;
  216. $this->virginUser = $virginUser;
  217. $this->eventDispatcher = $eventDispatcher;
  218. $this->configuratorService = $configuratorService;
  219. $this->autologinRequestRepository = $autologinRequestRepository;
  220. $this->errorPageLoader = $errorPageLoader;
  221. $this->logoutRoute = $logoutRoute;
  222. $this->sendPasswordRecoveryMailRoute = $sendPasswordRecoveryMailRoute;
  223. $this->resetPasswordRoute = $resetPasswordRoute;
  224. $this->customerRecoveryRepository = $customerRecoveryRepository;
  225. $this->session = $session;
  226. }
  227. /**
  228. * @Route("/appointment-new", name="frontend.appointment.new", options={"seo" = "false"}, methods={"POST"})
  229. * @throws \Exception
  230. */
  231. public function createAppointmentNew(Request $request, RequestDataBag $data, SalesChannelContext $salesChannelContext): Response
  232. {
  233. if (!$salesChannelContext->getCustomer() && !($lead = $this->virginUser->getCurrentLead())){
  234. return new Response("Permission denied", Response::HTTP_FORBIDDEN);
  235. }
  236. if ($data->get("appointmentType") == self::TYPE_ONSITE){
  237. $dateTimeObj = new DateTime($data->get("date")." ".$data->get("hour"));
  238. } else {
  239. $dateTimeObj = new DateTime("now");
  240. }
  241. /** @var ClubEntity $club */
  242. $club = $this->clubService->getClubById($data->get("clubId"), $salesChannelContext);
  243. $guidLead = $salesChannelContext->getCustomer() ? $salesChannelContext->getCustomer()->getCustomFields()['virgin_guid'] : $lead['guid_lead'];
  244. $formParams = [
  245. 'guid_lead' => $guidLead,
  246. 'guid_club' => $club->getGuidVirgin(),
  247. 'app_type' => $data->get("appointmentType"),
  248. 'app_date' => $dateTimeObj->format(DateTime::ATOM),
  249. 'note' => "Inserito da ecommerce",
  250. ];
  251. $resp = $this->restApiClient->insertAppointment($formParams);
  252. return new Response($resp['message'], $resp['code']);
  253. }
  254. /**
  255. * @Route("/walkin", name="frontend.walkin", options={"seo" = "false"}, methods={"GET"})
  256. */
  257. public function handleLeadLoadingPage(Request $request, RequestDataBag $data, SalesChannelContext $context)
  258. {
  259. $page = $this->loginPageLoader->load($request, $context);
  260. $request->getSession()->clear();
  261. $response = $this->renderStorefront('@Storefront/storefront/page/loading/walkin_loading.html.twig', [
  262. 'page' => $page,
  263. ]);
  264. $response->headers->setCookie(
  265. Cookie::create('leadUser', '', 1, '/', null, $request->isSecure(), true, false, 'Lax')
  266. );
  267. return $response;
  268. }
  269. /**
  270. * @Route("/walkinTA", name="frontend.walkinta", options={"seo" = "false"}, methods={"GET"})
  271. */
  272. public function handleLead(Request $request, RequestDataBag $data, SalesChannelContext $context)
  273. {
  274. $this->logger->log(Logger::DEBUG, 'Walkin request: ' . serialize($data));
  275. $leadInfo = $request->get('l');
  276. $decodedLeadInfo = json_decode(base64_decode($leadInfo));
  277. if(isset($decodedLeadInfo->mc_ExerpCode)){
  278. $_SESSION['mc_code'] = $decodedLeadInfo->mc_ExerpCode;
  279. $this->session->set("mc_code", $decodedLeadInfo->mc_ExerpCode);
  280. }
  281. $club_Guid = str_replace ("}", "", str_replace ("{", "", $decodedLeadInfo->club_Guid));
  282. $this->logger->log(Logger::DEBUG, 'Walkin decoded request: ' . serialize($data));
  283. $this->virginUser->checkPerson($decodedLeadInfo->email);
  284. if ($this->virginUser->getPersonType()!=$this->virginUser::PERSONTYPE_LEAD &&
  285. $this->virginUser->getPersonType()!=$this->virginUser::PERSONTYPE_LEADLAYER &&
  286. $this->virginUser->getPersonType()!=$this->virginUser::PERSONTYPE_EXSOCIO
  287. ){
  288. return $this->redirectToRoute('frontend.account.login.page');
  289. }
  290. try {
  291. $club = $this->clubService->getClubByGuid($club_Guid, $context);
  292. $fromCrm = $decodedLeadInfo->fromCrm ?? false;
  293. $this->session->set("fromCrm", $fromCrm);
  294. $this->virginUser->saveCurrentLead(
  295. null,
  296. $decodedLeadInfo->email,
  297. $decodedLeadInfo->nome,
  298. $decodedLeadInfo->cognome,
  299. $decodedLeadInfo->telefono,
  300. $club->getId(),
  301. false,
  302. (new \DateTime())->getTimestamp(),
  303. $context,
  304. $fromCrm
  305. );
  306. } catch (\Exception $e) {
  307. return $this->redirectToRoute('frontend.account.register.page');
  308. }
  309. return $this->redirectToRoute('frontend.configurator');
  310. }
  311. /**
  312. * @Route("/account/recover", name="frontend.account.recover.page", methods={"GET"})
  313. *
  314. * @throws CategoryNotFoundException
  315. * @throws InconsistentCriteriaIdsException
  316. * @throws MissingRequestParameterException
  317. */
  318. public function recoverAccountForm(Request $request, SalesChannelContext $context): Response
  319. {
  320. $page = $this->loginPageLoader->load($request, $context);
  321. return $this->renderStorefront('@Storefront/storefront/page/recover-password.html.twig', [
  322. 'page' => $page,
  323. ]);
  324. }
  325. /**
  326. * @Route("/account/recover", name="frontend.account.recover.request", methods={"POST"})
  327. * @throws VirginApiException
  328. */
  329. public function generateAccountRecovery(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
  330. {
  331. $email = $data->all()['email']['email'];
  332. $this->virginUser->checkPerson($email);
  333. if ($this->virginUser->getPersonType()==$this->virginUser::PERSONTYPE_LEAD || $this->virginUser->getPersonType()==$this->virginUser::PERSONTYPE_LEADLAYER){
  334. $this->addFlash('danger', $this->trans('lead-manager.account.emailIsNotRegistered'));
  335. return $this->redirectToRoute('frontend.account.register.page');
  336. } else {
  337. $this->restApiClient->requestGlobalPasswordReset($email);
  338. $this->session->set("recovery-email", $email);
  339. $this->session->set("recovery-timestamp", (new DateTime())->getTimestamp());
  340. return $this->redirectToRoute('frontend.account.recover.password.global');
  341. }
  342. }
  343. private function checkHash(string $hash, Context $context): bool
  344. {
  345. $criteria = new Criteria();
  346. $criteria->addFilter(
  347. new EqualsFilter('hash', $hash)
  348. );
  349. $recovery = $this->customerRecoveryRepository->search($criteria, $context)->first();
  350. $validDateTime = (new \DateTime())->sub(new \DateInterval('PT2H'));
  351. return $recovery && $validDateTime < $recovery->getCreatedAt();
  352. }
  353. /**
  354. * @Route("/account/recover/password", name="frontend.account.recover.password.page", methods={"GET"})
  355. *
  356. * @throws CategoryNotFoundException
  357. * @throws InconsistentCriteriaIdsException
  358. * @throws MissingRequestParameterException
  359. */
  360. public function resetPasswordForm(Request $request, SalesChannelContext $context): Response
  361. {
  362. $page = $this->loginPageLoader->load($request, $context);
  363. $hash = $request->get('hash');
  364. if (!$hash) {
  365. $this->addFlash('danger', $this->trans('account.passwordHashNotFound'));
  366. return $this->redirectToRoute('frontend.account.recover.request');
  367. }
  368. $customerHashCriteria = new Criteria();
  369. $customerHashCriteria->addFilter(new EqualsFilter('hash', $hash));
  370. $customerRecovery = $this->customerRecoveryRepository->search($customerHashCriteria, $context->getContext())->first();
  371. if ($customerRecovery === null) {
  372. $this->addFlash('danger', $this->trans('account.passwordHashNotFound'));
  373. return $this->redirectToRoute('frontend.account.recover.request');
  374. }
  375. if (!$this->checkHash($hash, $context->getContext())) {
  376. $this->addFlash('danger', $this->trans('account.passwordHashExpired'));
  377. return $this->redirectToRoute('frontend.account.recover.request');
  378. }
  379. return $this->renderStorefront('@Storefront/storefront/page/reset-password.html.twig', [
  380. 'page' => $page,
  381. 'hash' => $hash,
  382. 'formViolations' => $request->get('formViolations'),
  383. ]);
  384. }
  385. /**
  386. * @Route("/account/recover/password/global", name="frontend.account.recover.password.global", methods={"GET"})
  387. * */
  388. public function resetPasswordGlobalPage(Request $request, SalesChannelContext $context): Response
  389. {
  390. $email = $this->session->get("recovery-email");
  391. $timestamp = $this->session->get("recovery-timestamp");
  392. if (!$email || !$timestamp){
  393. $this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
  394. return $this->redirectToRoute('frontend.account.recover.request');
  395. }
  396. try {
  397. if ((new DateTime())->diff(new DateTime("@".$timestamp))->h > 24){
  398. $this->addFlash('danger', $this->trans('lead-manager.account.recovery.invalidTimestamp'));
  399. return $this->redirectToRoute('frontend.account.recover.request');
  400. }
  401. } catch (\Exception $e){
  402. $this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
  403. return $this->redirectToRoute('frontend.account.recover.request');
  404. }
  405. return $this->renderStorefront('@Storefront/storefront/page/reset-password.html.twig', [
  406. 'isGlobal' => true,
  407. 'email' => $email,
  408. ]);
  409. }
  410. /**
  411. * @Route("/account/recover/password", name="frontend.account.recover.password.reset", methods={"POST"})
  412. *
  413. * @throws InconsistentCriteriaIdsException
  414. */
  415. public function resetPassword(RequestDataBag $data, SalesChannelContext $context): Response
  416. {
  417. $hash = $data->get('password')->get('hash');
  418. try {
  419. if (!preg_match($this->restApiClient::PASSWORD_REGEX, $data->get('password')->get('newPassword'))){
  420. $this->addFlash('danger', $this->trans('account.passwordChangeNoSuccess'));
  421. return $this->forwardToRoute(
  422. 'frontend.account.recover.password.page',
  423. ['hash' => $hash, 'formViolations' => "Password not matching requirements", 'passwordFormViolation' => true]
  424. );
  425. }
  426. $customerHashCriteria = new Criteria();
  427. $customerHashCriteria->addFilter(new EqualsFilter('hash', $hash));
  428. $customerHashCriteria->addAssociation('customer');
  429. $customerRecovery = $this->customerRecoveryRepository->search($customerHashCriteria, $context->getContext())->first();
  430. $this->resetPasswordRoute->resetPassword($data->get('password')->toRequestDataBag(), $context);
  431. /** @var CustomerEntity $customer */
  432. $customer = $customerRecovery->getCustomer();
  433. $customerEmail = $customer->getEmail();
  434. $newPassword = $data->get('password')->get('newPassword');
  435. $checkPersonResp = $this->virginUser->checkPerson($customerEmail);
  436. $customFields = [
  437. 'lead_implicit_registration' => false
  438. ];
  439. $this->customerRepository->update([
  440. [
  441. 'id' => $customer->getId(),
  442. 'customFields' => $customFields,
  443. 'active' => true
  444. ],
  445. ], $context->getContext());
  446. } catch (ConstraintViolationException $formViolations) {
  447. $this->addFlash('danger', $this->trans('account.passwordChangeNoSuccess'));
  448. return $this->forwardToRoute(
  449. 'frontend.account.recover.password.page',
  450. ['hash' => $hash, 'formViolations' => $formViolations, 'passwordFormViolation' => true]
  451. );
  452. } catch (CustomerNotFoundByHashException $e) {
  453. $this->addFlash('danger', $this->trans('account.passwordChangeNoSuccess'));
  454. return $this->forwardToRoute('frontend.account.recover.request');
  455. } catch (CustomerRecoveryHashExpiredException $e) {
  456. $this->addFlash('danger', $this->trans('account.passwordHashExpired'));
  457. return $this->forwardToRoute('frontend.account.recover.request');
  458. }
  459. return $this->redirectToRoute('frontend.account.login.page');
  460. }
  461. /**
  462. * @Route("/account/recover/password/global", name="frontend.account.recover.password.reset.global", methods={"POST"})
  463. *
  464. * @throws VirginApiException
  465. */
  466. public function resetPasswordGlobal(RequestDataBag $data, SalesChannelContext $context): Response
  467. {
  468. $email = $data->get("email");
  469. $token = $data->get("token");
  470. $newPassword = $data->get("password")->get("newPassword");
  471. $this->virginUser->checkPerson($email);
  472. if ($this->virginUser->getPersonType()==$this->virginUser::PERSONTYPE_LEAD){
  473. $this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
  474. return $this->redirectToRoute('frontend.account.recover.request');
  475. }
  476. $response = $this->restApiClient->sendGlobalPasswordReset($email, $newPassword, $token);
  477. if (!$response['success']){
  478. $this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
  479. return $this->redirectToRoute('frontend.account.recover.request');
  480. }
  481. $this->addFlash('success', $this->trans('lead-manager.account.recovery.success'));
  482. return $this->redirectToRoute('frontend.account.login.page');
  483. }
  484. }