<?php
namespace App\Controller\Tenants\Tenant1;
use App\Entity\User;
use App\Exception\reCaptcha3Exception;
use App\Repository\{AuditRepository, SubscriptionRepository};
use App\Services\{OneTimeCodeService, ParameterService, reCaptcha3ValidatorService, TenantFlowService, TenantService};
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
class ProfileController extends AbstractController
{
private $tenant;
protected $tenantFlowService;
protected $csrfTokenManager;
private $auditRepository;
private $subscriptionRepository;
private $reCaptcha3ValidatorService;
private $oneTimeCodeService;
public function __construct(
TenantService $tenantService,
CsrfTokenManagerInterface $csrfTokenManager,
TenantFlowService $tenantFlowService,
AuditRepository $auditRepository,
SubscriptionRepository $subscriptionRepository,
ParameterService $parameterService,
reCaptcha3ValidatorService $reCaptcha3ValidatorService,
OneTimeCodeService $oneTimeCodeService
) {
$this->tenant = $tenantService->defineTenant();
$this->csrfTokenManager = $csrfTokenManager;
$this->tenantFlowService = $tenantFlowService;
$this->auditRepository = $auditRepository;
$this->subscriptionRepository = $subscriptionRepository;
$this->reCaptcha3ValidatorService = $reCaptcha3ValidatorService;
$this->reCaptcha3ValidatorService->setAccess(
$parameterService->getParameter($this->tenant->getSettingsArrayAssoc()['config'] ?? 'non-existent', 'reCaptcha3.secretKey'),
$parameterService->getParameter($this->tenant->getSettingsArrayAssoc()['config'] ?? 'non-existent', 'reCaptcha3.allowableScore')
);
$this->oneTimeCodeService = $oneTimeCodeService;
}
/**
* @Route("/profile", name="user_profile")
*/
public function profile(Request $request)
{
/** @var User $user */
$user = $this->getUser();
return $this->render("{$this->tenant->getRootPath()}/pages/profile.html.twig", [
'rootPath' => $this->tenant->getRootPath(),
'message' => $message ?? '',
'user' => $user,
]
+ $this->tenantFlowService->prepareTemplateArguments('plans', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('subscription', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('setupIntentClientSecretAndCard', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('shippingAddress', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('charges', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('signUp', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('stripe', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('frequency', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('menu', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('societies', $this->tenant)
);
}
/**
* @Route("/profile/change/name", name="user_profile_change_name", methods={"POST"})
* @Route("/profile/change/other", name="user_profile_change_other", methods={"POST"})
* @Route("/profile/change/shipping", name="user_profile_change_shipping", methods={"POST"})
* @Route("/profile/change/nameOnCard", name="user_profile_change_name_on_card", methods={"POST"})
* @Route("/profile/change/press", name="user_profile_change_press", methods={"POST"})
*/
public function profileChangeInfo(Request $request)
{
try {
/** @var User $user */
$user = $this->getUser();
if ( $csrf = $request->request->get('_csrf_token') ) {
switch ($request->get('_route')) {
case 'user_profile_change_name':
$token = 'ChangeName';
break;
case 'user_profile_change_other':
$token = 'ChangeOther';
break;
case 'user_profile_change_shipping':
$token = 'ShippingAddress';
break;
case 'user_profile_change_name_on_card':
$token = 'UpdateCardDetail';
break;
case 'user_profile_change_press':
$token = 'PressPlus';
break;
}
if ( ! $this->isCsrfTokenValid($token, $csrf) ) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$this->tenantFlowService->controlUserRequest($user, $request);
}
} catch (\Exception $exception) {
$errorMessage = $exception->getMessage();
}
return new JsonResponse([
'status' => (!isset($errorMessage)) ? true : false ,
'message' => $errorMessage ?? '',
]);
}
/**
* @Route("/profile/update/nameOnCard", name="user_profile_update_name_on_card", methods={"POST"})
*/
public function profileUpdateNameOnCard(Request $request)
{
try {
/** @var User $user */
$user = $this->getUser();
$this->tenantFlowService->controlUserRequest($user, $request);
} catch (\Exception $exception) {
$errorMessage = $exception->getMessage();
}
return new JsonResponse([
'status' => (!isset($errorMessage)) ? true : false ,
'message' => $errorMessage ?? '',
]);
}
/**
* @Route("/profile/password", name="user_password")
*/
public function profilePassword(Request $request)
{
try {
if ( 'GET' == $request->getMethod() ) {
$user = $this->oneTimeCodeService->findUserByCode($this->tenant, $request->query->get('code'));
if (is_null($user)) return $this->redirectToRoute('user_sign_in');
} elseif ( 'POST' == $request->getMethod() && $csrf = $request->request->get('_csrf_token') ) {
if ( ! $this->isCsrfTokenValid('ChangePassword', $csrf) ) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$this->reCaptcha3ValidatorService->setToken($request->request->get('reCAPTCHA_token'));
if ($this->reCaptcha3ValidatorService->validate()) {
throw new reCaptcha3Exception('reCaptcha3 validation failed.');
}
$user = $this->oneTimeCodeService->findUserByCode($this->tenant, $request->request->get('code'));
return $this->tenantFlowService->controlUserRequest($user, $request);
}
} catch (\Exception $exception) {
$message = $exception->getMessage();
}
return $this->render("{$this->tenant->getRootPath()}/pages/profile-password.html.twig", [
'rootPath' => $this->tenant->getRootPath(),
'message' => $message ?? '',
'activeTab' => 'password',
'user' => $user,
]
+ $this->tenantFlowService->prepareTemplateArguments('signUp', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('menu', $this->tenant)
);
}
/**
* @Route("/profile/change/password", name="user_profile_change_password", methods={"POST"})
*/
public function changePassword(Request $request)
{
try {
/** @var User $user */
$user = $this->getUser();
if ( 'POST' == $request->getMethod() && $csrf = $request->request->get('_csrf_token') ) {
if ( ! $this->isCsrfTokenValid('ChangePassword', $csrf) ) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$this->tenantFlowService->controlUserRequest($user, $request);
}
} catch (\Exception $exception) {
$errorMessage = $exception->getMessage();
}
return new JsonResponse([
'status' => (!isset($errorMessage)) ? true : false ,
'message' => $errorMessage ?? '',
]);
}
/**
* @Route("/profile/forgot/password", name="user_profile_forgot_password", methods={"POST"})
*/
public function forgotPassword(Request $request)
{
try {
/** @var User $user */
$user = $this->getUser();
if ( 'POST' == $request->getMethod() && $csrf = $request->request->get('_csrf_token') ) {
if ( ! $this->isCsrfTokenValid('ForgotPassword', $csrf) ) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$this->tenantFlowService->controlUserRequest($user, $request);
}
} catch (\Exception $exception) {
$errorMessage = $exception->getMessage();
}
return new JsonResponse([
'status' => (!isset($errorMessage)) ? true : false ,
'message' => $errorMessage ?? '',
]);
}
/**
* @Route("/profile/subscription/cancel", name="profile_subscription_cancel", methods={"POST"})
*/
public function profileSubscriptionCancel(Request $request)
{
try {
/** @var User $user */
$user = $this->getUser();
if ( 'POST' == $request->getMethod() && $csrf = $request->request->get('_csrf_token') ) {
if ( ! $this->isCsrfTokenValid('SubscriptionCancel', $csrf) ) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$this->tenantFlowService->controlUserRequest($user, $request);
}
} catch (\Exception $exception) {
$errorMessage = $exception->getMessage();
}
$data = [
'planHtml' => $this->refreshPlan(),
'popupHtml' => $this->renderPopup('renew')
];
return new JsonResponse([
'status' => (!isset($errorMessage)) ? true : false ,
'data' => (!isset($errorMessage)) ? $data : '' ,
'message' => $errorMessage ?? '',
]);
}
/**
* @Route("/profile/subscription/upgrade", name="profile_subscription_upgrade", methods={"POST"})
*/
public function profileSubscriptionUpgrade(Request $request)
{
try {
/** @var User $user */
$user = $this->getUser();
if ( 'POST' == $request->getMethod() && $csrf = $request->request->get('_csrf_token') ) {
if ( ! $this->isCsrfTokenValid('SubscriptionUpgrade', $csrf) ) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$this->tenantFlowService->controlUserRequest($user, $request);
}
} catch (\Exception $exception) {
$errorMessage = $exception->getMessage();
}
return new JsonResponse([
'status' => (!isset($errorMessage)) ? true : false ,
'data' => (!isset($errorMessage)) ? $this->refreshPlan() : '' ,
'message' => $errorMessage ?? '',
]);
}
/**
* @Route("/profile/check-updates", name="profile_check_updates", methods={"POST"})
*/
public function profileCheckUpdates(Request $request)
{
switch ($request->request->get('webhook')) {
case 'setup_intent.succeeded':
$flowName = 'WEBHOOK_SETUP_INTENT_SUCCEEDED';
$flowAction = 'WEBHOOK_SETUP_INTENT_UPDATE_DEFAULT_METHOD';
break;
case 'charge.succeeded':
$flowName = 'CONFIRM_USER_IS_PREMIUM_ONETIME_BY_WEBHOOK';
$flowAction = 'UPDATE_USER_FIELDS';
break;
case 'invoice.payment_succeeded':
$flowName = 'CONFIRM_USER_IS_PREMIUM_SUBSCRIPTION_BY_WEBHOOK';
$flowAction = 'UPDATE_USER_FIELDS';
break;
}
$user = $this->getUser();
$checking = $this->auditRepository->checkUpdates(
$user,
$flowName,
$flowAction,
$request->request->get('input')
);
$data = null;
if (!is_null($checking)) {
if ($request->request->get('webhook') == 'setup_intent.succeeded') {
$data = json_decode($checking->getOutput(), 1);
} else {
$setupIntentClientSecretAndCard = $this->tenantFlowService->prepareTemplateArguments('setupIntentClientSecretAndCard', $this->tenant);
$data = [
'planHtml' => $this->refreshPlan(),
'setupIntentClientSecretAndCard' => $setupIntentClientSecretAndCard,
'cardDetailsHtml' => $this->refreshCardDetails($setupIntentClientSecretAndCard),
'popupDiscontinue' => $this->renderPopup('discontinue'),
'popupUpgrade' => $this->renderPopup('upgrade'),
'popupPremium' => $this->renderPopup('renew'),
];
}
}
$subscription = null;
if ($request->request->get('webhook') == 'invoice.payment_succeeded') {
$subscription = (!is_null($checking))
? \json_decode($checking->getOutput(), 1)
: null
;
if (!is_null($subscription)) {
$subscriptionEntity = $this->subscriptionRepository->findOneBy(['externalId' => $subscription['subscriptionId']]);
}
}
$responseData = [
'status' => (!is_null($checking)) ? true : false,
'data' => $data,
'subscription' => $subscription,
'plan' => $user->getFieldsArrayAssoc()['chosenPlan'] ?? '',
];
if (isset($subscriptionEntity)) {
switch ($subscriptionEntity->getFrequency()) {
case 'MONTHLY':
$frequency = 'month';
break;
case 'ANNUALLY':
$frequency = 'year';
break;
default:
$frequency = '';
break;
}
$responseData['frequency'] = $frequency;
$responseData['amount'] = $subscriptionEntity->getRecurringChargeAmount();
}
return new JsonResponse($responseData);
}
public function refreshPlan()
{
return $this->renderView("tenants/tenant1/parts/plan.html.twig", [
'user' => $this->getUser(),
]
+ $this->tenantFlowService->prepareTemplateArguments('plans', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('subscription', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('societies', $this->tenant)
);
}
public function refreshCardDetails($setupIntentClientSecretAndCard)
{
return $this->renderView("tenants/tenant1/parts/cardDetails.html.twig", [
'user' => $this->getUser(),
]
+ $setupIntentClientSecretAndCard
+ $this->tenantFlowService->prepareTemplateArguments('subscription', $this->tenant)
);
}
public function renderPopup(string $type)
{
switch ($type) {
case 'renew':
return $this->renderView("tenants/tenant1/parts/planInGracePeriodDialog.html.twig", [
'user' => $this->getUser(),
'route' => 'user_profile'
]
+ $this->tenantFlowService->prepareTemplateArguments('frequency', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('countries', $this->tenant)
);
case 'discontinue':
return $this->renderView("tenants/tenant1/parts/subscriptionCancelationDialog.html.twig", [
'user' => $this->getUser(),
'route' => 'user_profile'
]
+ $this->tenantFlowService->prepareTemplateArguments('subscription', $this->tenant)
);
case 'upgrade':
return $this->renderView("tenants/tenant1/parts/UpgradePlanDialog.html.twig", [
'user' => $this->getUser(),
'route' => 'user_profile'
]
+ $this->tenantFlowService->prepareTemplateArguments('subscription', $this->tenant)
+ $this->tenantFlowService->prepareTemplateArguments('frequency', $this->tenant)
);
default:
// code...
break;
}
}
/**
* @Route("/user/getInfo", name="user_get_info", methods={"GET"})
*/
public function userGetInfo()
{
$user = $this->getUser();
if (!$user) {
return new JsonResponse([
'error' => 'general',
'message' => 'Error: An unexpected error has occurred. Please refresh the page or try again later.'
], 401);
}
return new JsonResponse(
[
'id' => $user->getId(),
'email' => $user->getEmail(),
'firstName' => $user->getFieldsArrayAssoc()['firstName'] ?? '',
'lastName' => $user->getFieldsArrayAssoc()['lastName'] ?? '',
'status' => $user->getStatus(),
]
);
}
}