Răsfoiți Sursa

Merge pull request #6099 from overleaf/jpa-recurly-redirect

[web] put hosted recurly pages behind a redirect

GitOrigin-RevId: 51a45dbcc0b74f1f1ae14eda9ed19a733e2d1334
Timothée Alby 4 ani în urmă
părinte
comite
5eed78a3e8

+ 1 - 0
services/web/app/src/Features/Subscription/RecurlyWrapper.js

@@ -1017,6 +1017,7 @@ const RecurlyWrapper = {
 }
 
 RecurlyWrapper.promises = {
+  getSubscription: promisify(RecurlyWrapper.getSubscription),
   updateAccountEmailAddress: promisify(updateAccountEmailAddress),
 }
 

+ 12 - 0
services/web/app/src/Features/Subscription/SubscriptionController.js

@@ -482,6 +482,17 @@ async function refreshUserFeatures(req, res) {
   res.sendStatus(200)
 }
 
+async function redirectToHostedPage(req, res) {
+  const userId = SessionManager.getLoggedInUserId(req.session)
+  const { pageType } = req.params
+  const url = await SubscriptionViewModelBuilder.promises.getRedirectToHostedPage(
+    userId,
+    pageType
+  )
+  logger.warn({ userId, pageType }, 'redirecting to recurly hosted page')
+  res.redirect(url)
+}
+
 module.exports = {
   plansPage: expressify(plansPage),
   paymentPage: expressify(paymentPage),
@@ -501,4 +512,5 @@ module.exports = {
   extendTrial: expressify(extendTrial),
   recurlyNotificationParser,
   refreshUserFeatures: expressify(refreshUserFeatures),
+  redirectToHostedPage: expressify(redirectToHostedPage),
 }

+ 6 - 0
services/web/app/src/Features/Subscription/SubscriptionRouter.js

@@ -47,6 +47,12 @@ module.exports = {
       SubscriptionController.canceledSubscription
     )
 
+    webRouter.get(
+      '/user/subscription/recurly/:pageType',
+      AuthenticationController.requireLogin(),
+      SubscriptionController.redirectToHostedPage
+    )
+
     webRouter.delete(
       '/subscription/group/user',
       AuthenticationController.requireLogin(),

+ 35 - 16
services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js

@@ -11,23 +11,44 @@ const _ = require('underscore')
 const async = require('async')
 const SubscriptionHelper = require('./SubscriptionHelper')
 const { promisify } = require('../../util/promises')
+const { InvalidError, NotFoundError } = require('../Errors/Errors')
+
+function buildHostedLink(type) {
+  return `/user/subscription/recurly/${type}`
+}
+
+async function getRedirectToHostedPage(userId, pageType) {
+  if (!['billing-details', 'account-management'].includes(pageType)) {
+    throw new InvalidError('unexpected page type')
+  }
+  const personalSubscription = await SubscriptionLocator.getUsersSubscription(
+    userId
+  )
+  const recurlySubscriptionId = personalSubscription?.recurlySubscription_id
+  if (!recurlySubscriptionId) {
+    throw new NotFoundError('not a recurly subscription')
+  }
+  const recurlySubscription = await RecurlyWrapper.promises.getSubscription(
+    recurlySubscriptionId,
+    { includeAccount: true }
+  )
 
-function buildHostedLink(recurlySubscription, type) {
   const recurlySubdomain = Settings.apis.recurly.subdomain
   const hostedLoginToken = recurlySubscription.account.hosted_login_token
+  if (!hostedLoginToken) {
+    throw new Error('recurly account does not have hosted login token')
+  }
   let path = ''
-  if (type === 'billingDetails') {
+  if (pageType === 'billing-details') {
     path = 'billing_info/edit?ht='
   }
-  if (hostedLoginToken && recurlySubdomain) {
-    return [
-      'https://',
-      recurlySubdomain,
-      '.recurly.com/account/',
-      path,
-      hostedLoginToken,
-    ].join('')
-  }
+  return [
+    'https://',
+    recurlySubdomain,
+    '.recurly.com/account/',
+    path,
+    hostedLoginToken,
+  ].join('')
 }
 
 function buildUsersSubscriptionViewModel(user, callback) {
@@ -178,11 +199,8 @@ function buildUsersSubscriptionViewModel(user, callback) {
           taxRate: recurlySubscription.tax_rate
             ? parseFloat(recurlySubscription.tax_rate._)
             : 0,
-          billingDetailsLink: buildHostedLink(
-            recurlySubscription,
-            'billingDetails'
-          ),
-          accountManagementLink: buildHostedLink(recurlySubscription),
+          billingDetailsLink: buildHostedLink('billing-details'),
+          accountManagementLink: buildHostedLink('account-management'),
           additionalLicenses,
           totalLicenses,
           nextPaymentDueAt: SubscriptionFormatters.formatDate(
@@ -335,5 +353,6 @@ module.exports = {
   buildPlansList,
   promises: {
     buildUsersSubscriptionViewModel: promisify(buildUsersSubscriptionViewModel),
+    getRedirectToHostedPage,
   },
 }