overleaf/services/web/app/src/Features/Subscription/SubscriptionViewModelBuilder.js

302 lines
9.2 KiB
JavaScript
Raw Normal View History

/* eslint-disable
handle-callback-err,
max-len,
no-return-assign,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS103: Rewrite code to no longer use __guard__
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const Settings = require('settings-sharelatex')
const RecurlyWrapper = require('./RecurlyWrapper')
const PlansLocator = require('./PlansLocator')
const SubscriptionFormatters = require('./SubscriptionFormatters')
const LimitationsManager = require('./LimitationsManager')
const SubscriptionLocator = require('./SubscriptionLocator')
const V1SubscriptionManager = require('./V1SubscriptionManager')
const InstitutionsGetter = require('../Institutions/InstitutionsGetter')
const PublishersGetter = require('../Publishers/PublishersGetter')
const sanitizeHtml = require('sanitize-html')
const logger = require('logger-sharelatex')
const _ = require('underscore')
const async = require('async')
const buildHostedLink = function(recurlySubscription, type) {
const recurlySubdomain = Settings.apis.recurly.subdomain
const hostedLoginToken = recurlySubscription.account.hosted_login_token
let path = ''
if (type === 'billingDetails') {
path = 'billing_info/edit?ht='
}
if (hostedLoginToken && recurlySubdomain) {
return [
'https://',
recurlySubdomain,
'.recurly.com/account/',
path,
hostedLoginToken
].join('')
}
}
module.exports = {
buildUsersSubscriptionViewModel(user, callback) {
if (callback == null) {
callback = function(error, data) {}
}
return async.auto(
{
personalSubscription(cb) {
return SubscriptionLocator.getUsersSubscription(user, cb)
},
recurlySubscription: [
'personalSubscription',
function(cb, { personalSubscription }) {
if (
(personalSubscription != null
? personalSubscription.recurlySubscription_id
: undefined) == null ||
(personalSubscription != null
? personalSubscription.recurlySubscription_id
: undefined) === ''
) {
return cb(null, null)
}
return RecurlyWrapper.getSubscription(
personalSubscription.recurlySubscription_id,
{ includeAccount: true },
cb
)
}
],
recurlyCoupons: [
'recurlySubscription',
function(cb, { recurlySubscription }) {
if (!recurlySubscription) {
return cb(null, null)
}
const accountId = recurlySubscription.account.account_code
return RecurlyWrapper.getAccountActiveCoupons(accountId, cb)
}
],
plan: [
'personalSubscription',
function(cb, { personalSubscription }) {
if (personalSubscription == null) {
return cb()
}
const plan = PlansLocator.findLocalPlanInSettings(
personalSubscription.planCode
)
if (plan == null) {
return cb(
new Error(
`No plan found for planCode '${
personalSubscription.planCode
}'`
)
)
}
return cb(null, plan)
}
],
memberGroupSubscriptions(cb) {
return SubscriptionLocator.getMemberSubscriptions(user, cb)
},
managedGroupSubscriptions(cb) {
return SubscriptionLocator.getManagedGroupSubscriptions(user, cb)
},
confirmedMemberInstitutions(cb) {
return InstitutionsGetter.getConfirmedInstitutions(user._id, cb)
},
managedInstitutions(cb) {
return InstitutionsGetter.getManagedInstitutions(user._id, cb)
},
managedPublishers(cb) {
return PublishersGetter.getManagedPublishers(user._id, cb)
},
v1SubscriptionStatus(cb) {
return V1SubscriptionManager.getSubscriptionStatusFromV1(
user._id,
function(error, status, v1Id) {
if (error != null) {
return cb(error)
}
return cb(null, status)
}
)
}
},
function(err, results) {
if (err != null) {
return callback(err)
}
let {
personalSubscription,
memberGroupSubscriptions,
managedGroupSubscriptions,
confirmedMemberInstitutions,
managedInstitutions,
managedPublishers,
v1SubscriptionStatus,
recurlySubscription,
recurlyCoupons,
plan
} = results
if (memberGroupSubscriptions == null) {
memberGroupSubscriptions = []
}
if (managedGroupSubscriptions == null) {
managedGroupSubscriptions = []
}
if (confirmedMemberInstitutions == null) {
confirmedMemberInstitutions = []
}
if (managedInstitutions == null) {
managedInstitutions = []
}
if (v1SubscriptionStatus == null) {
v1SubscriptionStatus = {}
}
if (recurlyCoupons == null) {
recurlyCoupons = []
}
if (
(personalSubscription != null
? personalSubscription.toObject
: undefined) != null
) {
// Downgrade from Mongoose object, so we can add a recurly and plan attribute
personalSubscription = personalSubscription.toObject()
}
if (plan != null) {
personalSubscription.plan = plan
}
if (personalSubscription != null && recurlySubscription != null) {
const tax =
(recurlySubscription != null
? recurlySubscription.tax_in_cents
: undefined) || 0
personalSubscription.recurly = {
tax,
taxRate: parseFloat(
__guard__(
recurlySubscription != null
? recurlySubscription.tax_rate
: undefined,
x => x._
)
),
billingDetailsLink: buildHostedLink(
recurlySubscription,
'billingDetails'
),
accountManagementLink: buildHostedLink(recurlySubscription),
price: SubscriptionFormatters.formatPrice(
(recurlySubscription != null
? recurlySubscription.unit_amount_in_cents
: undefined) + tax,
recurlySubscription != null
? recurlySubscription.currency
: undefined
),
nextPaymentDueAt: SubscriptionFormatters.formatDate(
recurlySubscription != null
? recurlySubscription.current_period_ends_at
: undefined
),
currency: recurlySubscription.currency,
state: recurlySubscription.state,
trialEndsAtFormatted: SubscriptionFormatters.formatDate(
recurlySubscription != null
? recurlySubscription.trial_ends_at
: undefined
),
trial_ends_at: recurlySubscription.trial_ends_at,
activeCoupons: recurlyCoupons
}
}
for (let memberGroupSubscription of Array.from(
memberGroupSubscriptions
)) {
if (memberGroupSubscription.teamNotice) {
memberGroupSubscription.teamNotice = sanitizeHtml(
memberGroupSubscription.teamNotice
)
}
}
return callback(null, {
personalSubscription,
managedGroupSubscriptions,
memberGroupSubscriptions,
confirmedMemberInstitutions,
managedInstitutions,
managedPublishers,
v1SubscriptionStatus
})
}
)
},
buildViewModel() {
const { plans } = Settings
const allPlans = {}
plans.forEach(plan => (allPlans[plan.planCode] = plan))
const result = { allPlans }
result.studentAccounts = _.filter(
plans,
plan => plan.planCode.indexOf('student') !== -1
)
result.groupMonthlyPlans = _.filter(
plans,
plan => plan.groupPlan && !plan.annual
)
result.groupAnnualPlans = _.filter(
plans,
plan => plan.groupPlan && plan.annual
)
result.individualMonthlyPlans = _.filter(
plans,
plan =>
!plan.groupPlan &&
!plan.annual &&
plan.planCode !== 'personal' && // Prevent the personal plan from appearing on the change-plans page
plan.planCode.indexOf('student') === -1
)
result.individualAnnualPlans = _.filter(
plans,
plan =>
!plan.groupPlan &&
plan.annual &&
plan.planCode.indexOf('student') === -1
)
return result
}
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}