<?php
namespace Virgin\LeadManager\Storefront\Controller;
use Monolog\Logger;
use RuntimeException;
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractSendPasswordRecoveryMailRoute;
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractResetPasswordRoute;
use Shopware\Core\Checkout\Customer\SalesChannel\AbstractLogoutRoute;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundByHashException;
use Shopware\Core\Checkout\Customer\Exception\CustomerNotFoundException;
use Shopware\Core\Checkout\Customer\Exception\CustomerRecoveryHashExpiredException;
use Shopware\Core\Checkout\Customer\SalesChannel\AccountService;
use Shopware\Core\Content\Category\Exception\CategoryNotFoundException;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Core\Framework\Validation\DataValidationDefinition;
use Shopware\Core\Framework\Validation\DataValidator;
use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
use Shopware\Core\System\SalesChannel\Context\SalesChannelContextPersister;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Shopware\Storefront\Controller\StorefrontController;
use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoader;
use Shopware\Storefront\Page\Navigation\Error\ErrorPageLoader;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Virgin\GDPRPlugin\Service\PrivacyService;
use Virgin\LeadManager\Custom\Autologin\AutologinRequestDefinition;
use Virgin\LeadManager\Service\AccountRegistrationServiceDecorator;
use Virgin\LeadManager\Storefront\Page\Contact\ContactPageLoader;
use Virgin\LeadManager\Utils\Services\LeadGenerationService;
use Virgin\ProductModelExtension\Custom\Club\ClubEntity;
use Virgin\ProductModelExtension\Services\ClubService;
use Virgin\SubscriptionsConfigurator\Utils\Services\SubscriptionsConfiguratorService;
use Virgin\SystemIntegration\Exception\VirginApiException;
use Virgin\SystemIntegration\Services\RestApiClient;
use Virgin\SystemIntegration\Services\VirginUser\VirginUser;
use Shopware\Core\Framework\Uuid\Uuid;
use DateTime;
use DateTimeZone;
/**
* @RouteScope(scopes={"storefront"})
*/
class LeadManagerController extends StorefrontController
{
const CALL = '1';
const APPOINTMENT = '2';
const REVOLUTION_CENTER_ID = 233;
/**
* @var AccountService
*/
private $accountService;
/**
* @var AccountRegistrationServiceDecorator
*/
private $accountRegistrationService;
/**
* @var SalesChannelContextPersister
*/
private $contextPersister;
/**
* @var LeadGenerationService
*/
private $leadService;
/**
* @var EntityRepository
*/
private $customerRepository;
/**
* @var DataValidator
*/
private $validator;
/**
* @var Logger
*/
private $logger;
/**
* @var ContactPageLoader
*/
private $contactPageLoader;
/**
* @var EntityRepository
*/
private $contactRepository;
/**
* @var EntityRepository
*/
private $contactTypeRepository;
/**
* @var EntityRepository
*/
private $virginUserTypeRepository;
/**
* @var EntityRepository
*/
private $clubRepository;
/**
* @var ClubService
*/
private $clubService;
/**
* @var RestApiClient
*/
private $restApiClient;
/**
* @var PrivacyService
*/
private $privacyService;
/**
* @var SystemConfigService
*/
private $systemConfigService;
/**
* @var AccountLoginPageLoader
*/
private $loginPageLoader;
/**
* @var VirginUser
*/
private $virginUser;
/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;
/** @var SubscriptionsConfiguratorService */
private $configuratorService;
/**
* @var EntityRepository
*/
private $autologinRequestRepository;
/**
* @var ErrorPageLoader
*/
private $errorPageLoader;
/**
* @var AbstractLogoutRoute
*/
private $logoutRoute;
/**
* @var AbstractSendPasswordRecoveryMailRoute
*/
private $sendPasswordRecoveryMailRoute;
/**
* @var AbstractResetPasswordRoute
*/
private $resetPasswordRoute;
/**
* @var EntityRepository
*/
private $customerRecoveryRepository;
/**
* @var SessionInterface
*/
private $session;
const TYPE_CALLCENTER = 1;
const TYPE_ONSITE = 2;
public function __construct(
AccountService $accountService,
AccountRegistrationServiceDecorator $accountRegistrationService,
SalesChannelContextPersister $contextPersister,
LeadGenerationService $leadService,
EntityRepository $customerRepository,
DataValidator $validator,
Logger $logger,
ContactPageLoader $contactPageLoader,
EntityRepository $contactRepository,
EntityRepository $contactTypeRepository,
EntityRepository $virginUserTypeRepository,
EntityRepository $clubRepository,
ClubService $clubService,
RestApiClient $restApiClient,
PrivacyService $privacyService,
SystemConfigService $systemConfigService,
AccountLoginPageLoader $loginPageLoader,
VirginUser $virginUser,
EventDispatcherInterface $eventDispatcher,
SubscriptionsConfiguratorService $configuratorService,
EntityRepository $autologinRequestRepository,
ErrorPageLoader $errorPageLoader,
AbstractLogoutRoute $logoutRoute,
AbstractSendPasswordRecoveryMailRoute $sendPasswordRecoveryMailRoute,
AbstractResetPasswordRoute $resetPasswordRoute,
EntityRepository $customerRecoveryRepository,
SessionInterface $session
)
{
$this->accountService = $accountService;
$this->accountRegistrationService = $accountRegistrationService;
$this->contextPersister = $contextPersister;
$this->leadService = $leadService;
$this->customerRepository = $customerRepository;
$this->validator = $validator;
$this->logger = $logger;
$this->contactPageLoader = $contactPageLoader;
$this->contactRepository = $contactRepository;
$this->contactTypeRepository = $contactTypeRepository;
$this->virginUserTypeRepository = $virginUserTypeRepository;
$this->clubRepository = $clubRepository;
$this->clubService = $clubService;
$this->restApiClient = $restApiClient;
$this->privacyService = $privacyService;
$this->systemConfigService = $systemConfigService;
$this->loginPageLoader = $loginPageLoader;
$this->virginUser = $virginUser;
$this->eventDispatcher = $eventDispatcher;
$this->configuratorService = $configuratorService;
$this->autologinRequestRepository = $autologinRequestRepository;
$this->errorPageLoader = $errorPageLoader;
$this->logoutRoute = $logoutRoute;
$this->sendPasswordRecoveryMailRoute = $sendPasswordRecoveryMailRoute;
$this->resetPasswordRoute = $resetPasswordRoute;
$this->customerRecoveryRepository = $customerRecoveryRepository;
$this->session = $session;
}
/**
* @Route("/appointment-new", name="frontend.appointment.new", options={"seo" = "false"}, methods={"POST"})
* @throws \Exception
*/
public function createAppointmentNew(Request $request, RequestDataBag $data, SalesChannelContext $salesChannelContext): Response
{
if (!$salesChannelContext->getCustomer() && !($lead = $this->virginUser->getCurrentLead())){
return new Response("Permission denied", Response::HTTP_FORBIDDEN);
}
if ($data->get("appointmentType") == self::TYPE_ONSITE){
$dateTimeObj = new DateTime($data->get("date")." ".$data->get("hour"));
} else {
$dateTimeObj = new DateTime("now");
}
/** @var ClubEntity $club */
$club = $this->clubService->getClubById($data->get("clubId"), $salesChannelContext);
$guidLead = $salesChannelContext->getCustomer() ? $salesChannelContext->getCustomer()->getCustomFields()['virgin_guid'] : $lead['guid_lead'];
$formParams = [
'guid_lead' => $guidLead,
'guid_club' => $club->getGuidVirgin(),
'app_type' => $data->get("appointmentType"),
'app_date' => $dateTimeObj->format(DateTime::ATOM),
'note' => "Inserito da ecommerce",
];
$resp = $this->restApiClient->insertAppointment($formParams);
return new Response($resp['message'], $resp['code']);
}
/**
* @Route("/walkin", name="frontend.walkin", options={"seo" = "false"}, methods={"GET"})
*/
public function handleLeadLoadingPage(Request $request, RequestDataBag $data, SalesChannelContext $context)
{
$page = $this->loginPageLoader->load($request, $context);
$request->getSession()->clear();
$response = $this->renderStorefront('@Storefront/storefront/page/loading/walkin_loading.html.twig', [
'page' => $page,
]);
$response->headers->setCookie(
Cookie::create('leadUser', '', 1, '/', null, $request->isSecure(), true, false, 'Lax')
);
return $response;
}
/**
* @Route("/walkinTA", name="frontend.walkinta", options={"seo" = "false"}, methods={"GET"})
*/
public function handleLead(Request $request, RequestDataBag $data, SalesChannelContext $context)
{
$this->logger->log(Logger::DEBUG, 'Walkin request: ' . serialize($data));
$leadInfo = $request->get('l');
$decodedLeadInfo = json_decode(base64_decode($leadInfo));
if(isset($decodedLeadInfo->mc_ExerpCode)){
$_SESSION['mc_code'] = $decodedLeadInfo->mc_ExerpCode;
$this->session->set("mc_code", $decodedLeadInfo->mc_ExerpCode);
}
$club_Guid = str_replace ("}", "", str_replace ("{", "", $decodedLeadInfo->club_Guid));
$this->logger->log(Logger::DEBUG, 'Walkin decoded request: ' . serialize($data));
$this->virginUser->checkPerson($decodedLeadInfo->email);
if ($this->virginUser->getPersonType()!=$this->virginUser::PERSONTYPE_LEAD &&
$this->virginUser->getPersonType()!=$this->virginUser::PERSONTYPE_LEADLAYER &&
$this->virginUser->getPersonType()!=$this->virginUser::PERSONTYPE_EXSOCIO
){
return $this->redirectToRoute('frontend.account.login.page');
}
try {
$club = $this->clubService->getClubByGuid($club_Guid, $context);
$fromCrm = $decodedLeadInfo->fromCrm ?? false;
$this->session->set("fromCrm", $fromCrm);
$this->virginUser->saveCurrentLead(
null,
$decodedLeadInfo->email,
$decodedLeadInfo->nome,
$decodedLeadInfo->cognome,
$decodedLeadInfo->telefono,
$club->getId(),
false,
(new \DateTime())->getTimestamp(),
$context,
$fromCrm
);
} catch (\Exception $e) {
return $this->redirectToRoute('frontend.account.register.page');
}
return $this->redirectToRoute('frontend.configurator');
}
/**
* @Route("/account/recover", name="frontend.account.recover.page", methods={"GET"})
*
* @throws CategoryNotFoundException
* @throws InconsistentCriteriaIdsException
* @throws MissingRequestParameterException
*/
public function recoverAccountForm(Request $request, SalesChannelContext $context): Response
{
$page = $this->loginPageLoader->load($request, $context);
return $this->renderStorefront('@Storefront/storefront/page/recover-password.html.twig', [
'page' => $page,
]);
}
/**
* @Route("/account/recover", name="frontend.account.recover.request", methods={"POST"})
* @throws VirginApiException
*/
public function generateAccountRecovery(Request $request, RequestDataBag $data, SalesChannelContext $context): Response
{
$email = $data->all()['email']['email'];
$this->virginUser->checkPerson($email);
if ($this->virginUser->getPersonType()==$this->virginUser::PERSONTYPE_LEAD || $this->virginUser->getPersonType()==$this->virginUser::PERSONTYPE_LEADLAYER){
$this->addFlash('danger', $this->trans('lead-manager.account.emailIsNotRegistered'));
return $this->redirectToRoute('frontend.account.register.page');
} else {
$this->restApiClient->requestGlobalPasswordReset($email);
$this->session->set("recovery-email", $email);
$this->session->set("recovery-timestamp", (new DateTime())->getTimestamp());
return $this->redirectToRoute('frontend.account.recover.password.global');
}
}
private function checkHash(string $hash, Context $context): bool
{
$criteria = new Criteria();
$criteria->addFilter(
new EqualsFilter('hash', $hash)
);
$recovery = $this->customerRecoveryRepository->search($criteria, $context)->first();
$validDateTime = (new \DateTime())->sub(new \DateInterval('PT2H'));
return $recovery && $validDateTime < $recovery->getCreatedAt();
}
/**
* @Route("/account/recover/password", name="frontend.account.recover.password.page", methods={"GET"})
*
* @throws CategoryNotFoundException
* @throws InconsistentCriteriaIdsException
* @throws MissingRequestParameterException
*/
public function resetPasswordForm(Request $request, SalesChannelContext $context): Response
{
$page = $this->loginPageLoader->load($request, $context);
$hash = $request->get('hash');
if (!$hash) {
$this->addFlash('danger', $this->trans('account.passwordHashNotFound'));
return $this->redirectToRoute('frontend.account.recover.request');
}
$customerHashCriteria = new Criteria();
$customerHashCriteria->addFilter(new EqualsFilter('hash', $hash));
$customerRecovery = $this->customerRecoveryRepository->search($customerHashCriteria, $context->getContext())->first();
if ($customerRecovery === null) {
$this->addFlash('danger', $this->trans('account.passwordHashNotFound'));
return $this->redirectToRoute('frontend.account.recover.request');
}
if (!$this->checkHash($hash, $context->getContext())) {
$this->addFlash('danger', $this->trans('account.passwordHashExpired'));
return $this->redirectToRoute('frontend.account.recover.request');
}
return $this->renderStorefront('@Storefront/storefront/page/reset-password.html.twig', [
'page' => $page,
'hash' => $hash,
'formViolations' => $request->get('formViolations'),
]);
}
/**
* @Route("/account/recover/password/global", name="frontend.account.recover.password.global", methods={"GET"})
* */
public function resetPasswordGlobalPage(Request $request, SalesChannelContext $context): Response
{
$email = $this->session->get("recovery-email");
$timestamp = $this->session->get("recovery-timestamp");
if (!$email || !$timestamp){
$this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
return $this->redirectToRoute('frontend.account.recover.request');
}
try {
if ((new DateTime())->diff(new DateTime("@".$timestamp))->h > 24){
$this->addFlash('danger', $this->trans('lead-manager.account.recovery.invalidTimestamp'));
return $this->redirectToRoute('frontend.account.recover.request');
}
} catch (\Exception $e){
$this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
return $this->redirectToRoute('frontend.account.recover.request');
}
return $this->renderStorefront('@Storefront/storefront/page/reset-password.html.twig', [
'isGlobal' => true,
'email' => $email,
]);
}
/**
* @Route("/account/recover/password", name="frontend.account.recover.password.reset", methods={"POST"})
*
* @throws InconsistentCriteriaIdsException
*/
public function resetPassword(RequestDataBag $data, SalesChannelContext $context): Response
{
$hash = $data->get('password')->get('hash');
try {
if (!preg_match($this->restApiClient::PASSWORD_REGEX, $data->get('password')->get('newPassword'))){
$this->addFlash('danger', $this->trans('account.passwordChangeNoSuccess'));
return $this->forwardToRoute(
'frontend.account.recover.password.page',
['hash' => $hash, 'formViolations' => "Password not matching requirements", 'passwordFormViolation' => true]
);
}
$customerHashCriteria = new Criteria();
$customerHashCriteria->addFilter(new EqualsFilter('hash', $hash));
$customerHashCriteria->addAssociation('customer');
$customerRecovery = $this->customerRecoveryRepository->search($customerHashCriteria, $context->getContext())->first();
$this->resetPasswordRoute->resetPassword($data->get('password')->toRequestDataBag(), $context);
/** @var CustomerEntity $customer */
$customer = $customerRecovery->getCustomer();
$customerEmail = $customer->getEmail();
$newPassword = $data->get('password')->get('newPassword');
$checkPersonResp = $this->virginUser->checkPerson($customerEmail);
$customFields = [
'lead_implicit_registration' => false
];
$this->customerRepository->update([
[
'id' => $customer->getId(),
'customFields' => $customFields,
'active' => true
],
], $context->getContext());
} catch (ConstraintViolationException $formViolations) {
$this->addFlash('danger', $this->trans('account.passwordChangeNoSuccess'));
return $this->forwardToRoute(
'frontend.account.recover.password.page',
['hash' => $hash, 'formViolations' => $formViolations, 'passwordFormViolation' => true]
);
} catch (CustomerNotFoundByHashException $e) {
$this->addFlash('danger', $this->trans('account.passwordChangeNoSuccess'));
return $this->forwardToRoute('frontend.account.recover.request');
} catch (CustomerRecoveryHashExpiredException $e) {
$this->addFlash('danger', $this->trans('account.passwordHashExpired'));
return $this->forwardToRoute('frontend.account.recover.request');
}
return $this->redirectToRoute('frontend.account.login.page');
}
/**
* @Route("/account/recover/password/global", name="frontend.account.recover.password.reset.global", methods={"POST"})
*
* @throws VirginApiException
*/
public function resetPasswordGlobal(RequestDataBag $data, SalesChannelContext $context): Response
{
$email = $data->get("email");
$token = $data->get("token");
$newPassword = $data->get("password")->get("newPassword");
$this->virginUser->checkPerson($email);
if ($this->virginUser->getPersonType()==$this->virginUser::PERSONTYPE_LEAD){
$this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
return $this->redirectToRoute('frontend.account.recover.request');
}
$response = $this->restApiClient->sendGlobalPasswordReset($email, $newPassword, $token);
if (!$response['success']){
$this->addFlash('danger', $this->trans('lead-manager.account.recovery.fail'));
return $this->redirectToRoute('frontend.account.recover.request');
}
$this->addFlash('success', $this->trans('lead-manager.account.recovery.success'));
return $this->redirectToRoute('frontend.account.login.page');
}
}