Subscription code decaf cleanup (#7918)

GitOrigin-RevId: 43adff9af7ca347808980823ac641db05129a79b
This commit is contained in:
Thomas 2022-05-17 12:10:19 +02:00 committed by Copybot
parent 2b2e9cfe45
commit 2d8e832be7
15 changed files with 680 additions and 975 deletions

View file

@ -1,23 +1,4 @@
/* eslint-disable
camelcase,
n/handle-callback-err,
max-len,
no-unused-vars,
n/no-deprecated-api,
*/
// 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 OError = require('@overleaf/o-error')
const querystring = require('querystring')
const crypto = require('crypto')
const request = require('request')
const Settings = require('@overleaf/settings')
const xml2js = require('xml2js')
@ -47,7 +28,7 @@ function updateAccountEmailAddress(accountId, newEmail, callback) {
body: requestBody,
},
(error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
RecurlyWrapper._parseAccountXml(body, callback)
@ -61,12 +42,11 @@ const RecurlyWrapper = {
_paypal: {
checkAccountExists(cache, next) {
const { user } = cache
const { subscriptionDetails } = cache
logger.debug(
{ user_id: user._id },
'checking if recurly account exists for user'
)
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `accounts/${user._id}`,
method: 'GET',
@ -96,7 +76,7 @@ const RecurlyWrapper = {
{ user_id: user._id },
'user appears to exist in recurly'
)
return RecurlyWrapper._parseAccountXml(
RecurlyWrapper._parseAccountXml(
responseBody,
function (err, account) {
if (err) {
@ -107,7 +87,7 @@ const RecurlyWrapper = {
}
cache.userExists = true
cache.account = account
return next(null, cache)
next(null, cache)
}
)
}
@ -142,7 +122,7 @@ const RecurlyWrapper = {
)
}
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: 'accounts',
method: 'POST',
@ -159,7 +139,7 @@ const RecurlyWrapper = {
)
return next(error)
}
return RecurlyWrapper._parseAccountXml(
RecurlyWrapper._parseAccountXml(
responseBody,
function (err, account) {
if (err) {
@ -169,7 +149,7 @@ const RecurlyWrapper = {
return next(err)
}
cache.account = account
return next(null, cache)
next(null, cache)
}
)
}
@ -178,12 +158,8 @@ const RecurlyWrapper = {
createBillingInfo(cache, next) {
const { user } = cache
const { recurlyTokenIds } = cache
const { subscriptionDetails } = cache
logger.debug({ user_id: user._id }, 'creating billing info in recurly')
const accountCode = __guard__(
cache != null ? cache.account : undefined,
x1 => x1.account_code
)
const accountCode = cache?.account?.account_code
if (!accountCode) {
return next(new Error('no account code at createBillingInfo stage'))
}
@ -196,7 +172,7 @@ const RecurlyWrapper = {
OError.tag(error, 'error building xml', { user_id: user._id })
)
}
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `accounts/${accountCode}/billing_info`,
method: 'POST',
@ -213,7 +189,7 @@ const RecurlyWrapper = {
)
return next(error)
}
return RecurlyWrapper._parseBillingInfoXml(
RecurlyWrapper._parseBillingInfoXml(
responseBody,
function (err, billingInfo) {
if (err) {
@ -224,7 +200,7 @@ const RecurlyWrapper = {
return next(err)
}
cache.billingInfo = billingInfo
return next(null, cache)
next(null, cache)
}
)
}
@ -238,10 +214,7 @@ const RecurlyWrapper = {
{ user_id: user._id },
'setting billing address and company info in recurly'
)
const accountCode = __guard__(
cache != null ? cache.account : undefined,
x1 => x1.account_code
)
const accountCode = cache?.account?.account_code
if (!accountCode) {
return next(
new Error('no account code at setAddressAndCompanyBillingInfo stage')
@ -270,7 +243,7 @@ const RecurlyWrapper = {
)
}
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `accounts/${accountCode}/billing_info`,
method: 'PUT',
@ -287,7 +260,7 @@ const RecurlyWrapper = {
)
return next(error)
}
return RecurlyWrapper._parseBillingInfoXml(
RecurlyWrapper._parseBillingInfoXml(
responseBody,
function (err, billingInfo) {
if (err) {
@ -297,7 +270,7 @@ const RecurlyWrapper = {
return next(err)
}
cache.billingInfo = billingInfo
return next(null, cache)
next(null, cache)
}
)
}
@ -329,7 +302,7 @@ const RecurlyWrapper = {
)
}
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: 'subscriptions',
method: 'POST',
@ -346,7 +319,7 @@ const RecurlyWrapper = {
)
return next(error)
}
return RecurlyWrapper._parseSubscriptionXml(
RecurlyWrapper._parseSubscriptionXml(
responseBody,
function (err, subscription) {
if (err) {
@ -356,7 +329,7 @@ const RecurlyWrapper = {
return next(err)
}
cache.subscription = subscription
return next(null, cache)
next(null, cache)
}
)
}
@ -378,7 +351,7 @@ const RecurlyWrapper = {
// passing a `cache` object along the way. The cache is initialized
// with required data, and `async.apply` to pass the cache to the first function
const cache = { user, recurlyTokenIds, subscriptionDetails }
return Async.waterfall(
Async.waterfall(
[
Async.apply(RecurlyWrapper._paypal.checkAccountExists, cache),
RecurlyWrapper._paypal.createAccount,
@ -404,7 +377,7 @@ const RecurlyWrapper = {
{ user_id: user._id },
'done creating paypal subscription for user'
)
return callback(null, result.subscription)
callback(null, result.subscription)
}
)
},
@ -447,7 +420,7 @@ const RecurlyWrapper = {
)
}
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: 'subscriptions',
method: 'POST',
@ -455,7 +428,7 @@ const RecurlyWrapper = {
expect422: true,
},
(error, response, responseBody) => {
if (error != null) {
if (error) {
return callback(error)
}
@ -493,9 +466,9 @@ const RecurlyWrapper = {
const { expect404, expect422 } = options
delete options.expect404
delete options.expect422
return request(options, function (error, response, body) {
request(options, function (error, response, body) {
if (
error == null &&
!error &&
response.statusCode !== 200 &&
response.statusCode !== 201 &&
response.statusCode !== 204 &&
@ -507,7 +480,7 @@ const RecurlyWrapper = {
err: error,
body,
options,
statusCode: response != null ? response.statusCode : undefined,
statusCode: response ? response.statusCode : undefined,
},
'error returned from recurly'
)
@ -516,27 +489,27 @@ const RecurlyWrapper = {
{ statusCode: response.statusCode }
)
}
return callback(error, response, body)
callback(error, response, body)
})
},
getSubscriptions(accountId, callback) {
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `accounts/${accountId}/subscriptions`,
},
(error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseXml(body, callback)
RecurlyWrapper._parseXml(body, callback)
}
)
},
getSubscription(subscriptionId, options, callback) {
let url
if (callback == null) {
if (!callback) {
callback = options
}
if (!options) {
@ -549,25 +522,25 @@ const RecurlyWrapper = {
url = `subscriptions/${subscriptionId}`
}
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url,
},
(error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseSubscriptionXml(
RecurlyWrapper._parseSubscriptionXml(
body,
(error, recurlySubscription) => {
if (error != null) {
if (error) {
return callback(error)
}
if (options.includeAccount) {
let accountId
if (
recurlySubscription.account != null &&
recurlySubscription.account.url != null
recurlySubscription.account &&
recurlySubscription.account.url
) {
accountId =
recurlySubscription.account.url.match(/accounts\/(.*)/)[1]
@ -577,18 +550,15 @@ const RecurlyWrapper = {
)
}
return RecurlyWrapper.getAccount(
accountId,
function (error, account) {
if (error != null) {
RecurlyWrapper.getAccount(accountId, function (error, account) {
if (error) {
return callback(error)
}
recurlySubscription.account = account
return callback(null, recurlySubscription)
}
)
callback(null, recurlySubscription)
})
} else {
return callback(null, recurlySubscription)
callback(null, recurlySubscription)
}
}
)
@ -604,52 +574,50 @@ const RecurlyWrapper = {
url: resource,
qs: queryParams,
}
if (cursor != null) {
if (cursor) {
opts.qs.cursor = cursor
}
return RecurlyWrapper.apiRequest(opts, (error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseXml(body, function (err, data) {
if (err != null) {
if (err) {
logger.warn({ err }, 'could not get accoutns')
callback(err)
return callback(err)
}
const items = data[resource]
allItems = allItems.concat(items)
logger.debug(
`got another ${items.length}, total now ${allItems.length}`
)
cursor = __guard__(
response.headers.link != null
? response.headers.link.match(/cursor=([0-9.]+%3A[0-9.]+)&/)
: undefined,
x1 => x1[1]
const match = response.headers.link?.match(
/cursor=([0-9.]+%3A[0-9.]+)&/
)
if (cursor != null) {
cursor = match && match[1]
if (cursor) {
cursor = decodeURIComponent(cursor)
return getPage(cursor)
} else {
return callback(err, allItems)
callback(err, allItems)
}
})
})
}
return getPage()
getPage()
},
getAccount(accountId, callback) {
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `accounts/${accountId}`,
},
(error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseAccountXml(body, callback)
RecurlyWrapper._parseAccountXml(body, callback)
}
)
},
@ -657,18 +625,18 @@ const RecurlyWrapper = {
updateAccountEmailAddress,
getAccountActiveCoupons(accountId, callback) {
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `accounts/${accountId}/redemptions`,
},
(error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseRedemptionsXml(
RecurlyWrapper._parseRedemptionsXml(
body,
function (error, redemptions) {
if (error != null) {
if (error) {
return callback(error)
}
const activeRedemptions = redemptions.filter(
@ -677,11 +645,11 @@ const RecurlyWrapper = {
const couponCodes = activeRedemptions.map(
redemption => redemption.coupon_code
)
return Async.map(
Async.map(
couponCodes,
RecurlyWrapper.getCoupon,
function (error, coupons) {
if (error != null) {
if (error) {
return callback(error)
}
return callback(null, coupons)
@ -695,21 +663,24 @@ const RecurlyWrapper = {
getCoupon(couponCode, callback) {
const opts = { url: `coupons/${couponCode}` }
return RecurlyWrapper.apiRequest(opts, (error, response, body) =>
RecurlyWrapper.apiRequest(opts, (error, response, body) => {
if (error) {
return callback(error)
}
RecurlyWrapper._parseCouponXml(body, callback)
)
})
},
getBillingInfo(accountId, callback) {
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `accounts/${accountId}/billing_info`,
},
(error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseXml(body, callback)
RecurlyWrapper._parseXml(body, callback)
}
)
},
@ -756,82 +727,85 @@ const RecurlyWrapper = {
)
}
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `subscriptions/${subscriptionId}`,
method: 'put',
body: requestBody,
},
(error, response, responseBody) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseSubscriptionXml(responseBody, callback)
RecurlyWrapper._parseSubscriptionXml(responseBody, callback)
}
)
},
createFixedAmmountCoupon(
coupon_code,
couponCode,
name,
currencyCode,
discount_in_cents,
plan_code,
discountInCents,
planCode,
callback
) {
const data = {
coupon_code,
coupon_code: couponCode,
name,
discount_type: 'dollars',
discount_in_cents: {},
plan_codes: {
plan_code,
plan_code: planCode,
},
applies_to_all_plans: false,
}
data.discount_in_cents[currencyCode] = discount_in_cents
data.discount_in_cents[currencyCode] = discountInCents
let requestBody
try {
requestBody = RecurlyWrapper._buildXml('coupon', data)
} catch (error) {
return callback(
OError.tag(error, 'error building xml', { coupon_code, name })
OError.tag(error, 'error building xml', {
couponCode,
name,
})
)
}
logger.debug({ coupon_code, requestBody }, 'creating coupon')
return RecurlyWrapper.apiRequest(
logger.debug({ couponCode, requestBody }, 'creating coupon')
RecurlyWrapper.apiRequest(
{
url: 'coupons',
method: 'post',
body: requestBody,
},
(error, response, responseBody) => {
if (error != null) {
logger.warn({ err: error, coupon_code }, 'error creating coupon')
if (error) {
logger.warn({ err: error, couponCode }, 'error creating coupon')
}
return callback(error)
callback(error)
}
)
},
lookupCoupon(coupon_code, callback) {
return RecurlyWrapper.apiRequest(
lookupCoupon(couponCode, callback) {
RecurlyWrapper.apiRequest(
{
url: `coupons/${coupon_code}`,
url: `coupons/${couponCode}`,
},
(error, response, body) => {
if (error != null) {
if (error) {
return callback(error)
}
return RecurlyWrapper._parseXml(body, callback)
RecurlyWrapper._parseXml(body, callback)
}
)
},
redeemCoupon(account_code, coupon_code, callback) {
redeemCoupon(accountCode, couponCode, callback) {
const data = {
account_code,
account_code: accountCode,
currency: 'USD',
}
let requestBody
@ -839,28 +813,31 @@ const RecurlyWrapper = {
requestBody = RecurlyWrapper._buildXml('redemption', data)
} catch (error) {
return callback(
OError.tag(error, 'error building xml', { account_code, coupon_code })
OError.tag(error, 'error building xml', {
accountCode,
couponCode,
})
)
}
logger.debug(
{ account_code, coupon_code, requestBody },
{ accountCode, couponCode, requestBody },
'redeeming coupon for user'
)
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `coupons/${coupon_code}/redeem`,
url: `coupons/${couponCode}/redeem`,
method: 'post',
body: requestBody,
},
(error, response, responseBody) => {
if (error != null) {
if (error) {
logger.warn(
{ err: error, account_code, coupon_code },
{ err: error, accountCode, couponCode },
'error redeeming coupon'
)
}
return callback(error)
callback(error)
}
)
},
@ -869,49 +846,46 @@ const RecurlyWrapper = {
if (daysUntilExpire == null) {
daysUntilExpire = 7
}
const next_renewal_date = new Date()
next_renewal_date.setDate(next_renewal_date.getDate() + daysUntilExpire)
const nextRenewalDate = new Date()
nextRenewalDate.setDate(nextRenewalDate.getDate() + daysUntilExpire)
logger.debug(
{ subscriptionId, daysUntilExpire },
'Exending Free trial for user'
)
return RecurlyWrapper.apiRequest(
RecurlyWrapper.apiRequest(
{
url: `/subscriptions/${subscriptionId}/postpone?next_renewal_date=${next_renewal_date}&bulk=false`,
url: `/subscriptions/${subscriptionId}/postpone?next_renewal_date=${nextRenewalDate}&bulk=false`,
method: 'put',
},
(error, response, responseBody) => {
if (error != null) {
if (error) {
logger.warn(
{ err: error, subscriptionId, daysUntilExpire },
'error exending trial'
)
}
return callback(error)
callback(error)
}
)
},
listAccountActiveSubscriptions(account_id, callback) {
if (callback == null) {
callback = function () {}
}
return RecurlyWrapper.apiRequest(
listAccountActiveSubscriptions(accountId, callback) {
RecurlyWrapper.apiRequest(
{
url: `accounts/${account_id}/subscriptions`,
url: `accounts/${accountId}/subscriptions`,
qs: {
state: 'active',
},
expect404: true,
},
function (error, response, body) {
if (error != null) {
if (error) {
return callback(error)
}
if (response.statusCode === 404) {
return callback(null, [])
callback(null, [])
} else {
return RecurlyWrapper._parseSubscriptionsXml(body, callback)
RecurlyWrapper._parseSubscriptionsXml(body, callback)
}
}
)
@ -955,60 +929,46 @@ const RecurlyWrapper = {
})
},
_parseSubscriptionsXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(
xml,
'subscriptions',
callback
)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'subscriptions', callback)
},
_parseSubscriptionXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(
xml,
'subscription',
callback
)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'subscription', callback)
},
_parseAccountXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(xml, 'account', callback)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'account', callback)
},
_parseBillingInfoXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(
xml,
'billing_info',
callback
)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'billing_info', callback)
},
_parseRedemptionsXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(xml, 'redemptions', callback)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'redemptions', callback)
},
_parseCouponXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(xml, 'coupon', callback)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'coupon', callback)
},
_parseErrorsXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(xml, 'errors', callback)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'errors', callback)
},
_parseInvoicesXml(xml, callback) {
return RecurlyWrapper._parseXmlAndGetAttribute(xml, 'invoices', callback)
RecurlyWrapper._parseXmlAndGetAttribute(xml, 'invoices', callback)
},
_parseXmlAndGetAttribute(xml, attribute, callback) {
return RecurlyWrapper._parseXml(xml, function (error, data) {
if (error != null) {
RecurlyWrapper._parseXml(xml, function (error, data) {
if (error) {
return callback(error)
}
if (data != null && data[attribute] != null) {
return callback(null, data[attribute])
if (data && data[attribute] != null) {
callback(null, data[attribute])
} else {
return callback(
new Error("I don't understand the response from Recurly")
)
callback(new Error("I don't understand the response from Recurly"))
}
})
},
@ -1016,10 +976,10 @@ const RecurlyWrapper = {
_parseXml(xml, callback) {
function convertDataTypes(data) {
let key, value
if (data != null && data.$ != null) {
if (data && data.$) {
if (data.$.nil === 'nil') {
data = null
} else if (data.$.href != null) {
} else if (data.$.href) {
data.url = data.$.href
delete data.$
} else if (data.$.type === 'integer') {
@ -1042,7 +1002,7 @@ const RecurlyWrapper = {
}
if (data instanceof Array) {
data = Array.from(data).map(entry => convertDataTypes(entry))
data = data.map(entry => convertDataTypes(entry))
} else if (typeof data === 'object') {
for (key in data) {
value = data[key]
@ -1057,12 +1017,12 @@ const RecurlyWrapper = {
explicitArray: false,
emptyTag: '',
})
return parser.parseString(xml, function (error, data) {
if (error != null) {
parser.parseString(xml, function (error, data) {
if (error) {
return callback(error)
}
const result = convertDataTypes(data)
return callback(null, result)
callback(null, result)
})
},
@ -1150,9 +1110,3 @@ function getAddressFromSubscriptionDetails(
return addressObject
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}

View file

@ -1,16 +1,4 @@
/* eslint-disable
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const dateformat = require('dateformat')
const settings = require('@overleaf/settings')
const currenySymbols = {
EUR: '€',
@ -28,7 +16,7 @@ const currenySymbols = {
module.exports = {
formatPrice(priceInCents, currency) {
if (currency == null) {
if (!currency) {
currency = 'USD'
}
let string = priceInCents + ''
@ -48,7 +36,7 @@ module.exports = {
},
formatDate(date) {
if (date == null) {
if (!date) {
return null
}
return dateformat(date, 'dS mmmm yyyy')

View file

@ -1,107 +1,62 @@
/* eslint-disable
camelcase,
n/handle-callback-err,
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* 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 async = require('async')
const _ = require('underscore')
const { promisify } = require('util')
const SubscriptionUpdater = require('./SubscriptionUpdater')
const SubscriptionLocator = require('./SubscriptionLocator')
const UserGetter = require('../User/UserGetter')
const { Subscription } = require('../../models/Subscription')
const LimitationsManager = require('./LimitationsManager')
const logger = require('@overleaf/logger')
const OneTimeTokenHandler = require('../Security/OneTimeTokenHandler')
const EmailHandler = require('../Email/EmailHandler')
const settings = require('@overleaf/settings')
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
const UserMembershipViewModel = require('../UserMembership/UserMembershipViewModel')
const SubscriptionGroupHandler = {
removeUserFromGroup(subscriptionId, userToRemove_id, callback) {
return SubscriptionUpdater.removeUserFromGroup(
removeUserFromGroup(subscriptionId, userIdToRemove, callback) {
SubscriptionUpdater.removeUserFromGroup(
subscriptionId,
userToRemove_id,
userIdToRemove,
callback
)
},
replaceUserReferencesInGroups(oldId, newId, callback) {
return Subscription.updateOne(
Subscription.updateOne(
{ admin_id: oldId },
{ admin_id: newId },
function (error) {
if (error != null) {
if (error) {
return callback(error)
}
return replaceInArray(
replaceInArray(
Subscription,
'manager_ids',
oldId,
newId,
function (error) {
if (error != null) {
if (error) {
return callback(error)
}
return replaceInArray(
Subscription,
'member_ids',
oldId,
newId,
callback
)
replaceInArray(Subscription, 'member_ids', oldId, newId, callback)
}
)
}
)
},
isUserPartOfGroup(user_id, subscription_id, callback) {
if (callback == null) {
callback = function () {}
}
return SubscriptionLocator.getSubscriptionByMemberIdAndId(
user_id,
subscription_id,
isUserPartOfGroup(userId, subscriptionId, callback) {
SubscriptionLocator.getSubscriptionByMemberIdAndId(
userId,
subscriptionId,
function (err, subscription) {
let partOfGroup
if (subscription != null) {
if (subscription) {
partOfGroup = true
} else {
partOfGroup = false
}
return callback(err, partOfGroup)
callback(err, partOfGroup)
}
)
},
getTotalConfirmedUsersInGroup(subscription_id, callback) {
if (callback == null) {
callback = function () {}
}
return SubscriptionLocator.getSubscription(
subscription_id,
(err, subscription) =>
callback(
err,
__guard__(
subscription != null ? subscription.member_ids : undefined,
x => x.length
)
)
getTotalConfirmedUsersInGroup(subscriptionId, callback) {
SubscriptionLocator.getSubscription(subscriptionId, (err, subscription) =>
callback(err, subscription?.member_ids?.length)
)
},
}
@ -126,12 +81,6 @@ function replaceInArray(model, property, oldValue, newValue, callback) {
})
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}
SubscriptionGroupHandler.promises = {
getTotalConfirmedUsersInGroup: promisify(
SubscriptionGroupHandler.getTotalConfirmedUsersInGroup

View file

@ -11,16 +11,13 @@ const PlansLocator = require('./PlansLocator')
const SubscriptionHelper = require('./SubscriptionHelper')
function validateNoSubscriptionInRecurly(userId, callback) {
if (callback == null) {
callback = function () {}
}
RecurlyWrapper.listAccountActiveSubscriptions(
userId,
function (error, subscriptions) {
if (subscriptions == null) {
if (!subscriptions) {
subscriptions = []
}
if (error != null) {
if (error) {
return callback(error)
}
if (subscriptions.length > 0) {
@ -28,7 +25,7 @@ function validateNoSubscriptionInRecurly(userId, callback) {
subscriptions[0],
userId,
function (error) {
if (error != null) {
if (error) {
return callback(error)
}
callback(null, false)
@ -48,7 +45,7 @@ function createSubscription(
callback
) {
validateNoSubscriptionInRecurly(user._id, function (error, valid) {
if (error != null) {
if (error) {
return callback(error)
}
if (!valid) {
@ -59,14 +56,14 @@ function createSubscription(
subscriptionDetails,
recurlyTokenIds,
function (error, recurlySubscription) {
if (error != null) {
if (error) {
return callback(error)
}
return SubscriptionUpdater.syncSubscription(
recurlySubscription,
user._id,
function (error) {
if (error != null) {
if (error) {
return callback(error)
}
return callback()
@ -93,14 +90,14 @@ function updateSubscription(user, planCode, couponCode, callback) {
return async.series(
[
function (cb) {
if (couponCode == null) {
if (!couponCode) {
return cb()
}
RecurlyWrapper.getSubscription(
subscription.recurlySubscription_id,
{ includeAccount: true },
function (err, usersSubscription) {
if (err != null) {
if (err) {
return cb(err)
}
RecurlyWrapper.redeemCoupon(
@ -134,7 +131,7 @@ function updateSubscription(user, planCode, couponCode, callback) {
subscription.recurlySubscription_id,
{ planCode, timeframe },
function (error, subscriptionChange) {
if (error != null) {
if (error) {
return cb(error)
}
// v2 recurly API wants a UUID, but UUID isn't included in the subscription change response
@ -167,7 +164,7 @@ function cancelPendingSubscriptionChange(user, callback) {
RecurlyClient.removeSubscriptionChangeByUuid(
subscription.recurlySubscription_id,
function (error) {
if (error != null) {
if (error) {
return callback(error)
}
callback()
@ -194,7 +191,7 @@ function cancelSubscription(user, callback) {
RecurlyClient.cancelSubscriptionByUuid(
subscription.recurlySubscription_id,
function (error) {
if (error != null) {
if (error) {
return callback(error)
}
const emailOpts = {
@ -208,7 +205,7 @@ function cancelSubscription(user, callback) {
'canceledSubscription',
emailOpts,
err => {
if (err != null) {
if (err) {
logger.warn(
{ err },
'failed to send confirmation email for subscription cancellation'
@ -242,14 +239,14 @@ function reactivateSubscription(user, callback) {
RecurlyClient.reactivateSubscriptionByUuid(
subscription.recurlySubscription_id,
function (error) {
if (error != null) {
if (error) {
return callback(error)
}
EmailHandler.sendEmail(
'reactivatedSubscription',
{ to: user.email },
err => {
if (err != null) {
if (err) {
logger.warn(
{ err },
'failed to send reactivation confirmation email'
@ -272,17 +269,17 @@ function syncSubscription(recurlySubscription, requesterData, callback) {
recurlySubscription.uuid,
{ includeAccount: true },
function (error, recurlySubscription) {
if (error != null) {
if (error) {
return callback(error)
}
User.findById(
recurlySubscription.account.account_code,
{ _id: 1 },
function (error, user) {
if (error != null) {
if (error) {
return callback(error)
}
if (user == null) {
if (!user) {
return callback(new Error('no user found'))
}
SubscriptionUpdater.syncSubscription(

View file

@ -1,15 +1,3 @@
/* eslint-disable
camelcase,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const { promisify } = require('util')
const { Subscription } = require('../../models/Subscription')
const { DeletedSubscription } = require('../../models/DeletedSubscription')
@ -17,62 +5,55 @@ const logger = require('@overleaf/logger')
require('./GroupPlansData') // make sure dynamic group plans are loaded
const SubscriptionLocator = {
getUsersSubscription(user_or_id, callback) {
const user_id = SubscriptionLocator._getUserId(user_or_id)
Subscription.findOne({ admin_id: user_id }, function (err, subscription) {
logger.debug({ user_id }, 'got users subscription')
getUsersSubscription(userOrId, callback) {
const userId = SubscriptionLocator._getUserId(userOrId)
Subscription.findOne({ admin_id: userId }, function (err, subscription) {
logger.debug({ userId }, 'got users subscription')
callback(err, subscription)
})
},
getUserIndividualSubscription(user_or_id, callback) {
const user_id = SubscriptionLocator._getUserId(user_or_id)
getUserIndividualSubscription(userOrId, callback) {
const userId = SubscriptionLocator._getUserId(userOrId)
Subscription.findOne(
{ admin_id: user_id, groupPlan: false },
{ admin_id: userId, groupPlan: false },
function (err, subscription) {
logger.debug({ user_id }, 'got users individual subscription')
logger.debug({ userId }, 'got users individual subscription')
callback(err, subscription)
}
)
},
getManagedGroupSubscriptions(user_or_id, callback) {
if (callback == null) {
callback = function () {}
}
getManagedGroupSubscriptions(userOrId, callback) {
Subscription.find({
manager_ids: user_or_id,
manager_ids: userOrId,
groupPlan: true,
})
.populate('admin_id')
.exec(callback)
},
getMemberSubscriptions(user_or_id, callback) {
const user_id = SubscriptionLocator._getUserId(user_or_id)
Subscription.find({ member_ids: user_id })
getMemberSubscriptions(userOrId, callback) {
const userId = SubscriptionLocator._getUserId(userOrId)
Subscription.find({ member_ids: userId })
.populate('admin_id')
.exec(callback)
},
getSubscription(subscription_id, callback) {
Subscription.findOne({ _id: subscription_id }, callback)
getSubscription(subscriptionId, callback) {
Subscription.findOne({ _id: subscriptionId }, callback)
},
getSubscriptionByMemberIdAndId(user_id, subscription_id, callback) {
getSubscriptionByMemberIdAndId(userId, subscriptionId, callback) {
Subscription.findOne(
{ member_ids: user_id, _id: subscription_id },
{ member_ids: userId, _id: subscriptionId },
{ _id: 1 },
callback
)
},
getGroupSubscriptionsMemberOf(user_id, callback) {
Subscription.find(
{ member_ids: user_id },
{ _id: 1, planCode: 1 },
callback
)
getGroupSubscriptionsMemberOf(userId, callback) {
Subscription.find({ member_ids: userId }, { _id: 1, planCode: 1 }, callback)
},
getGroupsWithEmailInvite(email, callback) {
@ -96,11 +77,11 @@ const SubscriptionLocator = {
)
},
_getUserId(user_or_id) {
if (user_or_id != null && user_or_id._id != null) {
return user_or_id._id
} else if (user_or_id != null) {
return user_or_id
_getUserId(userOrId) {
if (userOrId && userOrId._id) {
return userOrId._id
} else if (userOrId) {
return userOrId
}
},
}

View file

@ -1,13 +1,3 @@
/* eslint-disable
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const AuthenticationController = require('../Authentication/AuthenticationController')
const SubscriptionController = require('./SubscriptionController')
const SubscriptionGroupController = require('./SubscriptionGroupController')

View file

@ -1,17 +1,4 @@
/* eslint-disable
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const settings = require('@overleaf/settings')
const logger = require('@overleaf/logger')
const TeamInvitesHandler = require('./TeamInvitesHandler')
const SessionManager = require('../Authentication/SessionManager')
const SubscriptionLocator = require('./SubscriptionLocator')
@ -23,7 +10,7 @@ module.exports = {
const teamManagerId = SessionManager.getLoggedInUserId(req.session)
const subscription = req.entity
const email = EmailHelper.parseEmail(req.body.email)
if (email == null) {
if (!email) {
return res.status(422).json({
error: {
code: 'invalid_email',
@ -32,12 +19,12 @@ module.exports = {
})
}
return TeamInvitesHandler.createInvite(
TeamInvitesHandler.createInvite(
teamManagerId,
subscription,
email,
function (err, inviteUserData) {
if (err != null) {
if (err) {
if (err.alreadyInTeam) {
return res.status(400).json({
error: {
@ -56,7 +43,7 @@ module.exports = {
}
return next(err)
}
return res.json({ user: inviteUserData })
res.json({ user: inviteUserData })
}
)
},
@ -65,10 +52,10 @@ module.exports = {
const { token } = req.params
const userId = SessionManager.getLoggedInUserId(req.session)
return TeamInvitesHandler.getInvite(
TeamInvitesHandler.getInvite(
token,
function (err, invite, teamSubscription) {
if (err != null) {
if (err) {
return next(err)
}
@ -76,21 +63,21 @@ module.exports = {
return ErrorController.notFound(req, res, next)
}
return SubscriptionLocator.getUsersSubscription(
SubscriptionLocator.getUsersSubscription(
userId,
function (err, personalSubscription) {
if (err != null) {
if (err) {
return next(err)
}
const hasIndividualRecurlySubscription =
personalSubscription != null &&
personalSubscription.planCode.match(/(free|trial)/) == null &&
personalSubscription &&
!personalSubscription.planCode.match(/(free|trial)/) &&
personalSubscription.groupPlan === false &&
personalSubscription.recurlySubscription_id != null &&
personalSubscription.recurlySubscription_id &&
personalSubscription.recurlySubscription_id !== ''
return res.render('subscriptions/team/invite', {
res.render('subscriptions/team/invite', {
inviterName: invite.inviterName,
inviteToken: invite.token,
hasIndividualRecurlySubscription,
@ -107,35 +94,31 @@ module.exports = {
const { token } = req.params
const userId = SessionManager.getLoggedInUserId(req.session)
return TeamInvitesHandler.acceptInvite(
token,
userId,
function (err, results) {
if (err != null) {
TeamInvitesHandler.acceptInvite(token, userId, function (err, results) {
if (err) {
return next(err)
}
return res.sendStatus(204)
}
)
res.sendStatus(204)
})
},
revokeInvite(req, res, next) {
const subscription = req.entity
const email = EmailHelper.parseEmail(req.params.email)
const teamManagerId = SessionManager.getLoggedInUserId(req.session)
if (email == null) {
if (!email) {
return res.sendStatus(400)
}
return TeamInvitesHandler.revokeInvite(
TeamInvitesHandler.revokeInvite(
teamManagerId,
subscription,
email,
function (err, results) {
if (err != null) {
if (err) {
return next(err)
}
return res.sendStatus(204)
res.sendStatus(204)
}
)
},

View file

@ -1,16 +1,3 @@
/* eslint-disable
n/handle-callback-err,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* 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
*/
let V1SubscriptionManager
const UserGetter = require('../User/UserGetter')
const request = require('requestretry')
@ -20,10 +7,7 @@ const { promisifyAll } = require('../../util/promises')
module.exports = V1SubscriptionManager = {
getSubscriptionsFromV1(userId, callback) {
if (callback == null) {
callback = function () {}
}
return V1SubscriptionManager._v1Request(
V1SubscriptionManager._v1Request(
userId,
{
method: 'GET',
@ -36,10 +20,7 @@ module.exports = V1SubscriptionManager = {
},
getSubscriptionStatusFromV1(userId, callback) {
if (callback == null) {
callback = function () {}
}
return V1SubscriptionManager._v1Request(
V1SubscriptionManager._v1Request(
userId,
{
method: 'GET',
@ -52,10 +33,7 @@ module.exports = V1SubscriptionManager = {
},
cancelV1Subscription(userId, callback) {
if (callback == null) {
callback = function () {}
}
return V1SubscriptionManager._v1Request(
V1SubscriptionManager._v1Request(
userId,
{
method: 'DELETE',
@ -68,34 +46,23 @@ module.exports = V1SubscriptionManager = {
},
v1IdForUser(userId, callback) {
if (callback == null) {
callback = function () {}
}
return UserGetter.getUser(
userId,
{ 'overleaf.id': 1 },
function (err, user) {
if (err != null) {
UserGetter.getUser(userId, { 'overleaf.id': 1 }, function (err, user) {
if (err) {
return callback(err)
}
const v1Id = __guard__(
user != null ? user.overleaf : undefined,
x => x.id
)
return callback(null, v1Id)
}
)
const v1Id = user?.overleaf?.id
callback(null, v1Id)
})
},
// v1 accounts created before migration to v2 had github and mendeley for free
// but these are now paid-for features for new accounts (v1id > cutoff)
getGrandfatheredFeaturesForV1User(v1Id) {
const cutoff = settings.v1GrandfatheredFeaturesUidCutoff
if (cutoff == null) {
if (!cutoff) {
return {}
}
if (v1Id == null) {
if (!v1Id) {
return {}
}
@ -107,18 +74,15 @@ module.exports = V1SubscriptionManager = {
},
_v1Request(userId, options, callback) {
if (callback == null) {
callback = function () {}
}
if (!settings.apis.v1.url) {
return callback(null, null)
}
return V1SubscriptionManager.v1IdForUser(userId, function (err, v1Id) {
if (err != null) {
V1SubscriptionManager.v1IdForUser(userId, function (err, v1Id) {
if (err) {
return callback(err)
}
if (v1Id == null) {
if (!v1Id) {
return callback(null, null, null)
}
const url = options.url(v1Id)
@ -141,7 +105,7 @@ module.exports = V1SubscriptionManager = {
requestOptions.maxAttempts = 0
}
request(requestOptions, function (error, response, body) {
if (error != null) {
if (error) {
return callback(
new V1ConnectionError({
message: 'no v1 connection',
@ -180,12 +144,6 @@ module.exports = V1SubscriptionManager = {
},
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}
module.exports.promises = promisifyAll(module.exports, {
without: ['getGrandfatheredFeaturesForV1User'],
})

View file

@ -1,5 +1,3 @@
// TODO: This file was created by bulk-decaffeinate.
// Sanity-check the conversion and remove this comment.
module.exports = [
{
feature: 'number_collab',

View file

@ -1,16 +1,3 @@
/* eslint-disable
max-len,
mocha/handle-done-callback,
no-return-assign,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
const { assert, expect } = require('chai')
@ -172,13 +159,13 @@ describe('SubscriptionController', function () {
this.req.body = {}
this.req.query = { planCode: '123123' }
return (this.stubbedCurrencyCode = 'GBP')
this.stubbedCurrencyCode = 'GBP'
})
describe('plansPage', function () {
beforeEach(function () {
this.req.ip = '1234.3123.3131.333 313.133.445.666 653.5345.5345.534'
return this.GeoIpLookup.promises.getCurrencyCode.resolves({
this.GeoIpLookup.promises.getCurrencyCode.resolves({
currencyCode: this.stubbedCurrencyCode,
})
})
@ -234,7 +221,7 @@ describe('SubscriptionController', function () {
this.SubscriptionHandler.promises.validateNoSubscriptionInRecurly = sinon
.stub()
.resolves(true)
return this.GeoIpLookup.promises.getCurrencyCode.resolves({
this.GeoIpLookup.promises.getCurrencyCode.resolves({
currencyCode: this.stubbedCurrencyCode,
})
})
@ -244,7 +231,7 @@ describe('SubscriptionController', function () {
this.LimitationsManager.promises.userHasV1OrV2Subscription.resolves(
false
)
return this.PlansLocator.findLocalPlanInSettings.returns({})
this.PlansLocator.findLocalPlanInSettings.returns({})
})
describe('with a valid plan code', function () {
@ -266,9 +253,9 @@ describe('SubscriptionController', function () {
)
this.res.redirect = url => {
url.should.equal('/user/subscription?hasSubscription=true')
return done()
done()
}
return this.SubscriptionController.paymentPage(this.req, this.res)
this.SubscriptionController.paymentPage(this.req, this.res)
})
})
@ -286,7 +273,7 @@ describe('SubscriptionController', function () {
done()
}
)
return this.SubscriptionController.paymentPage(this.req, this.res)
this.SubscriptionController.paymentPage(this.req, this.res)
})
})
@ -295,7 +282,7 @@ describe('SubscriptionController', function () {
this.LimitationsManager.promises.userHasV1OrV2Subscription.resolves(
false
)
return this.PlansLocator.findLocalPlanInSettings.returns({})
this.PlansLocator.findLocalPlanInSettings.returns({})
})
it('should use the set currency from the query string', function (done) {
@ -303,18 +290,18 @@ describe('SubscriptionController', function () {
this.res.render = (page, opts) => {
opts.currency.should.equal('EUR')
opts.currency.should.not.equal(this.stubbedCurrencyCode)
return done()
done()
}
return this.SubscriptionController.paymentPage(this.req, this.res)
this.SubscriptionController.paymentPage(this.req, this.res)
})
it('should upercase the currency code', function (done) {
this.req.query.currency = 'eur'
this.res.render = (page, opts) => {
opts.currency.should.equal('EUR')
return done()
done()
}
return this.SubscriptionController.paymentPage(this.req, this.res)
this.SubscriptionController.paymentPage(this.req, this.res)
})
it('should use the geo ip currency if non is provided', function (done) {
@ -348,9 +335,9 @@ describe('SubscriptionController', function () {
)
this.res.redirect = url => {
url.should.equal('/user/subscription?hasSubscription=true')
return done()
done()
}
return this.SubscriptionController.paymentPage(this.req, this.res)
this.SubscriptionController.paymentPage(this.req, this.res)
})
})
})
@ -434,17 +421,17 @@ describe('SubscriptionController', function () {
expect(this.data.personalSubscription).to.deep.equal(
this.personalSubscription
)
return expect(this.data.memberGroupSubscriptions).to.deep.equal(
expect(this.data.memberGroupSubscriptions).to.deep.equal(
this.memberGroupSubscriptions
)
})
it('should load the user', function () {
return expect(this.data.user).to.deep.equal(this.user)
expect(this.data.user).to.deep.equal(this.user)
})
it('should load the plans', function () {
return expect(this.data.plans).to.deep.equal(this.plans)
expect(this.data.plans).to.deep.equal(this.plans)
})
})
@ -452,7 +439,7 @@ describe('SubscriptionController', function () {
beforeEach(function (done) {
this.res = {
sendStatus() {
return done()
done()
},
}
sinon.spy(this.res, 'sendStatus')
@ -469,7 +456,7 @@ describe('SubscriptionController', function () {
this.recurlyTokenIds.threeDSecureActionResult
this.req.body.subscriptionDetails = this.subscriptionDetails
this.LimitationsManager.userHasV1OrV2Subscription.yields(null, false)
return this.SubscriptionController.createSubscription(this.req, this.res)
this.SubscriptionController.createSubscription(this.req, this.res)
})
it('should send the user and subscriptionId to the handler', function (done) {
@ -480,12 +467,12 @@ describe('SubscriptionController', function () {
this.recurlyTokenIds
)
.should.equal(true)
return done()
done()
})
it('should redurect to the subscription page', function (done) {
this.res.sendStatus.calledWith(201).should.equal(true)
return done()
done()
})
})
@ -551,7 +538,7 @@ describe('SubscriptionController', function () {
}
)
return this.SubscriptionController.createSubscription(this.req, this.res)
this.SubscriptionController.createSubscription(this.req, this.res)
})
it('should handle invalid error', function (done) {
@ -566,7 +553,7 @@ describe('SubscriptionController', function () {
done()
})
return this.SubscriptionController.createSubscription(this.req, this.res)
this.SubscriptionController.createSubscription(this.req, this.res)
})
})
@ -574,25 +561,25 @@ describe('SubscriptionController', function () {
beforeEach(function (done) {
this.res = {
redirect() {
return done()
done()
},
}
sinon.spy(this.res, 'redirect')
this.plan_code = '1234'
this.req.body.plan_code = this.plan_code
return this.SubscriptionController.updateSubscription(this.req, this.res)
this.SubscriptionController.updateSubscription(this.req, this.res)
})
it('should send the user and subscriptionId to the handler', function (done) {
this.SubscriptionHandler.updateSubscription
.calledWith(this.user, this.plan_code)
.should.equal(true)
return done()
done()
})
it('should redurect to the subscription page', function (done) {
this.res.redirect.calledWith('/user/subscription').should.equal(true)
return done()
done()
})
})
@ -629,26 +616,23 @@ describe('SubscriptionController', function () {
beforeEach(function (done) {
this.res = {
redirect() {
return done()
done()
},
}
sinon.spy(this.res, 'redirect')
return this.SubscriptionController.reactivateSubscription(
this.req,
this.res
)
this.SubscriptionController.reactivateSubscription(this.req, this.res)
})
it('should tell the handler to reactivate this user', function (done) {
this.SubscriptionHandler.reactivateSubscription
.calledWith(this.user)
.should.equal(true)
return done()
done()
})
it('should redurect to the subscription page', function (done) {
this.res.redirect.calledWith('/user/subscription').should.equal(true)
return done()
done()
})
})
@ -656,25 +640,25 @@ describe('SubscriptionController', function () {
beforeEach(function (done) {
this.res = {
redirect() {
return done()
done()
},
}
sinon.spy(this.res, 'redirect')
return this.SubscriptionController.cancelSubscription(this.req, this.res)
this.SubscriptionController.cancelSubscription(this.req, this.res)
})
it('should tell the handler to cancel this user', function (done) {
this.SubscriptionHandler.cancelSubscription
.calledWith(this.user)
.should.equal(true)
return done()
done()
})
it('should redurect to the subscription page', function (done) {
this.res.redirect
.calledWith('/user/subscription/canceled')
.should.equal(true)
return done()
done()
})
})
@ -699,21 +683,21 @@ describe('SubscriptionController', function () {
}
this.res = {
sendStatus() {
return done()
done()
},
}
sinon.spy(this.res, 'sendStatus')
return this.SubscriptionController.recurlyCallback(this.req, this.res)
this.SubscriptionController.recurlyCallback(this.req, this.res)
})
it('should tell the SubscriptionHandler to process the recurly callback', function (done) {
this.SubscriptionHandler.syncSubscription.called.should.equal(true)
return done()
done()
})
it('should send a 200', function (done) {
this.res.sendStatus.calledWith(200)
return done()
done()
})
})
@ -771,11 +755,11 @@ describe('SubscriptionController', function () {
}
this.res = {
sendStatus() {
return done()
done()
},
}
sinon.spy(this.res, 'sendStatus')
return this.SubscriptionController.recurlyCallback(this.req, this.res)
this.SubscriptionController.recurlyCallback(this.req, this.res)
})
it('should not call the subscriptionshandler', function () {
@ -786,7 +770,7 @@ describe('SubscriptionController', function () {
})
it('should respond with a 200 status', function () {
return this.res.sendStatus.calledWith(200)
this.res.sendStatus.calledWith(200)
})
})
})
@ -796,9 +780,9 @@ describe('SubscriptionController', function () {
this.LimitationsManager.userHasV2Subscription.callsArgWith(1, null, false)
this.res.redirect = function (url) {
url.should.equal('/user/subscription/plans')
return done()
done()
}
return this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.req,
this.res
)
@ -814,9 +798,9 @@ describe('SubscriptionController', function () {
this.res.render = function (view, opts) {
view.should.equal('subscriptions/upgradeToAnnual')
opts.planName.should.equal('student')
return done()
done()
}
return this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.req,
this.res
)
@ -831,9 +815,9 @@ describe('SubscriptionController', function () {
)
this.res.render = function (view, opts) {
opts.planName.should.equal('collaborator')
return done()
done()
}
return this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.req,
this.res
)
@ -848,9 +832,9 @@ describe('SubscriptionController', function () {
)
this.res.render = function (view, opts) {
opts.planName.should.equal('annual')
return done()
done()
}
return this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.SubscriptionController.renderUpgradeToAnnualPlanPage(
this.req,
this.res
)
@ -867,13 +851,10 @@ describe('SubscriptionController', function () {
this.SubscriptionHandler.updateSubscription
.calledWith(this.user, 'student-annual', 'STUDENTCODEHERE')
.should.equal(true)
return done()
done()
}
return this.SubscriptionController.processUpgradeToAnnualPlan(
this.req,
this.res
)
this.SubscriptionController.processUpgradeToAnnualPlan(this.req, this.res)
})
it('should get the collaborator coupon code', function (done) {
@ -883,13 +864,10 @@ describe('SubscriptionController', function () {
this.SubscriptionHandler.updateSubscription
.calledWith(this.user, 'collaborator-annual', 'COLLABORATORCODEHERE')
.should.equal(true)
return done()
done()
}
return this.SubscriptionController.processUpgradeToAnnualPlan(
this.req,
this.res
)
this.SubscriptionController.processUpgradeToAnnualPlan(this.req, this.res)
})
})
})

View file

@ -1,21 +1,7 @@
/* eslint-disable
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:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
const { assert } = require('chai')
const modulePath =
'../../../../app/src/Features/Subscription/SubscriptionGroupController'
const MockResponse = require('../helpers/MockResponse')
describe('SubscriptionGroupController', function () {
beforeEach(function () {
@ -55,13 +41,13 @@ describe('SubscriptionGroupController', function () {
},
}
return (this.Controller = SandboxedModule.require(modulePath, {
this.Controller = SandboxedModule.require(modulePath, {
requires: {
'./SubscriptionGroupHandler': this.GroupHandler,
'./SubscriptionLocator': this.SubscriptionLocator,
'../Authentication/SessionManager': this.SessionManager,
},
}))
})
})
describe('removeUserFromGroup', function () {
@ -75,16 +61,15 @@ describe('SubscriptionGroupController', function () {
this.GroupHandler.removeUserFromGroup
.calledWith(this.subscriptionId, userIdToRemove)
.should.equal(true)
return done()
done()
},
}
return this.Controller.removeUserFromGroup(this.req, res)
this.Controller.removeUserFromGroup(this.req, res)
})
})
describe('removeSelfFromGroup', function () {
it('gets subscription and remove user', function (done) {
const userIdToRemove = '31231'
this.req.query = { subscriptionId: this.subscriptionId }
const memberUserIdToremove = 123456789
this.req.session.user._id = memberUserIdToremove
@ -100,10 +85,10 @@ describe('SubscriptionGroupController', function () {
this.subscriptionId,
memberUserIdToremove
)
return done()
done()
},
}
return this.Controller.removeSelfFromGroup(this.req, res)
this.Controller.removeSelfFromGroup(this.req, res)
})
})
})

View file

@ -1,20 +1,6 @@
/* eslint-disable
n/handle-callback-err,
max-len,
no-dupe-keys,
no-return-assign,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
const { assert, expect } = require('chai')
const { expect } = require('chai')
const modulePath =
'../../../../app/src/Features/Subscription/SubscriptionGroupHandler'
@ -85,7 +71,7 @@ describe('SubscriptionGroupHandler', function () {
},
}
return (this.Handler = SandboxedModule.require(modulePath, {
this.Handler = SandboxedModule.require(modulePath, {
requires: {
'../User/UserCreator': this.UserCreator,
'./SubscriptionUpdater': this.SubscriptionUpdater,
@ -102,19 +88,20 @@ describe('SubscriptionGroupHandler', function () {
'../UserMembership/UserMembershipViewModel':
this.UserMembershipViewModel,
},
}))
})
})
describe('removeUserFromGroup', function () {
it('should call the subscription updater to remove the user', function (done) {
return this.Handler.removeUserFromGroup(
this.Handler.removeUserFromGroup(
this.adminUser_id,
this.user._id,
err => {
if (err) return done(err)
this.SubscriptionUpdater.removeUserFromGroup
.calledWith(this.adminUser_id, this.user._id)
.should.equal(true)
return done()
done()
}
)
})
@ -124,15 +111,13 @@ describe('SubscriptionGroupHandler', function () {
beforeEach(function (done) {
this.oldId = 'ba5eba11'
this.newId = '5ca1ab1e'
return this.Handler.replaceUserReferencesInGroups(
this.oldId,
this.newId,
() => done()
this.Handler.replaceUserReferencesInGroups(this.oldId, this.newId, () =>
done()
)
})
it('replaces the admin_id', function () {
return this.Subscription.updateOne
this.Subscription.updateOne
.calledWith({ admin_id: this.oldId }, { admin_id: this.newId })
.should.equal(true)
})
@ -145,7 +130,7 @@ describe('SubscriptionGroupHandler', function () {
)
.should.equal(true)
return this.Subscription.updateMany
this.Subscription.updateMany
.calledWith(
{ manager_ids: 'ba5eba11' },
{ $pull: { manager_ids: 'ba5eba11' } }
@ -161,7 +146,7 @@ describe('SubscriptionGroupHandler', function () {
)
.should.equal(true)
return this.Subscription.updateMany
this.Subscription.updateMany
.calledWith(
{ member_ids: this.oldId },
{ $pull: { member_ids: this.oldId } }
@ -172,7 +157,7 @@ describe('SubscriptionGroupHandler', function () {
describe('isUserPartOfGroup', function () {
beforeEach(function () {
return (this.subscription_id = '123ed13123')
this.subscription_id = '123ed13123'
})
it('should return true when user is part of subscription', function (done) {
@ -181,12 +166,13 @@ describe('SubscriptionGroupHandler', function () {
null,
{ _id: this.subscription_id }
)
return this.Handler.isUserPartOfGroup(
this.Handler.isUserPartOfGroup(
this.user_id,
this.subscription_id,
(err, partOfGroup) => {
if (err) return done(err)
partOfGroup.should.equal(true)
return done()
done()
}
)
})
@ -196,12 +182,13 @@ describe('SubscriptionGroupHandler', function () {
2,
null
)
return this.Handler.isUserPartOfGroup(
this.Handler.isUserPartOfGroup(
this.user_id,
this.subscription_id,
(err, partOfGroup) => {
if (err) return done(err)
partOfGroup.should.equal(false)
return done()
done()
}
)
})
@ -210,30 +197,29 @@ describe('SubscriptionGroupHandler', function () {
describe('getTotalConfirmedUsersInGroup', function () {
describe('for existing subscriptions', function () {
beforeEach(function () {
return (this.subscription.member_ids = ['12321', '3121321'])
this.subscription.member_ids = ['12321', '3121321']
})
it('should call the subscription locator and return 2 users', function (done) {
return this.Handler.getTotalConfirmedUsersInGroup(
this.Handler.getTotalConfirmedUsersInGroup(
this.subscription_id,
(err, count) => {
if (err) return done(err)
this.SubscriptionLocator.getSubscription
.calledWith(this.subscription_id)
.should.equal(true)
count.should.equal(2)
return done()
done()
}
)
})
})
describe('for nonexistent subscriptions', function () {
it('should return undefined', function (done) {
return this.Handler.getTotalConfirmedUsersInGroup(
'fake-id',
(err, count) => {
this.Handler.getTotalConfirmedUsersInGroup('fake-id', (err, count) => {
if (err) return done(err)
expect(count).not.to.exist
return done()
}
)
done()
})
})
})
})

View file

@ -1,21 +1,7 @@
/* eslint-disable
n/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:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
const modulePath =
'../../../../app/src/Features/Subscription/SubscriptionLocator'
const { assert } = require('chai')
describe('Subscription Locator Tests', function () {
beforeEach(function () {
@ -29,7 +15,7 @@ describe('Subscription Locator Tests', function () {
findOne: sinon.stub().yields(),
find: sinon.stub().yields(),
}
return (this.SubscriptionLocator = SandboxedModule.require(modulePath, {
this.SubscriptionLocator = SandboxedModule.require(modulePath, {
requires: {
'./GroupPlansData': {},
'../../models/Subscription': {
@ -39,45 +25,47 @@ describe('Subscription Locator Tests', function () {
DeletedSubscription: this.DeletedSubscription,
},
},
}))
})
})
describe('finding users subscription', function () {
it('should send the users features', function (done) {
this.Subscription.findOne.callsArgWith(1, null, this.subscription)
return this.SubscriptionLocator.getUsersSubscription(
this.SubscriptionLocator.getUsersSubscription(
this.user,
(err, subscription) => {
if (err) return done(err)
this.Subscription.findOne
.calledWith({ admin_id: this.user._id })
.should.equal(true)
subscription.should.equal(this.subscription)
return done()
done()
}
)
})
it('should error if not found', function (done) {
this.Subscription.findOne.callsArgWith(1, 'not found')
return this.SubscriptionLocator.getUsersSubscription(
this.SubscriptionLocator.getUsersSubscription(
this.user,
(err, subscription) => {
err.should.exist
return done()
done()
}
)
})
it('should take a user id rather than the user object', function (done) {
this.Subscription.findOne.callsArgWith(1, null, this.subscription)
return this.SubscriptionLocator.getUsersSubscription(
this.SubscriptionLocator.getUsersSubscription(
this.user._id,
(err, subscription) => {
if (err) return done(err)
this.Subscription.findOne
.calledWith({ admin_id: this.user._id })
.should.equal(true)
subscription.should.equal(this.subscription)
return done()
done()
}
)
})

View file

@ -1,19 +1,4 @@
/* eslint-disable
camelcase,
n/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:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const SandboxedModule = require('sandboxed-module')
const assert = require('assert')
const path = require('path')
const modulePath = path.join(
__dirname,
@ -45,13 +30,13 @@ describe('V1SubscriptionManager', function () {
})
this.userId = 'abcd'
this.v1UserId = 42
return (this.user = {
this.user = {
_id: this.userId,
email: 'user@example.com',
overleaf: {
id: this.v1UserId,
},
})
}
})
describe('getGrandfatheredFeaturesForV1User', function () {
@ -60,7 +45,7 @@ describe('V1SubscriptionManager', function () {
expect(
this.V1SubscriptionManager.getGrandfatheredFeaturesForV1User(100)
).to.eql({})
return done()
done()
})
})
@ -72,14 +57,14 @@ describe('V1SubscriptionManager', function () {
github: true,
mendeley: true,
})
return done()
done()
})
})
})
describe('_v1Request', function () {
beforeEach(function () {
return (this.UserGetter.getUser = sinon.stub().yields(null, this.user))
this.UserGetter.getUser = sinon.stub().yields(null, this.user)
})
describe('when v1IdForUser produces an error', function () {
@ -87,8 +72,8 @@ describe('V1SubscriptionManager', function () {
this.V1SubscriptionManager.v1IdForUser = sinon
.stub()
.yields(new Error('woops'))
return (this.call = cb => {
return this.V1SubscriptionManager._v1Request(
this.call = cb => {
this.V1SubscriptionManager._v1Request(
this.user_id,
{
url() {
@ -97,20 +82,20 @@ describe('V1SubscriptionManager', function () {
},
cb
)
})
}
})
it('should not call request', function (done) {
return this.call((err, planCode) => {
this.call(() => {
expect(this.request.callCount).to.equal(0)
return done()
done()
})
})
it('should produce an error', function (done) {
return this.call((err, planCode) => {
this.call((err, planCode) => {
expect(err).to.exist
return done()
done()
})
})
})
@ -118,8 +103,8 @@ describe('V1SubscriptionManager', function () {
describe('when v1IdForUser does not find a user', function () {
beforeEach(function () {
this.V1SubscriptionManager.v1IdForUser = sinon.stub().yields(null, null)
return (this.call = cb => {
return this.V1SubscriptionManager._v1Request(
this.call = cb => {
this.V1SubscriptionManager._v1Request(
this.user_id,
{
url() {
@ -128,20 +113,21 @@ describe('V1SubscriptionManager', function () {
},
cb
)
})
}
})
it('should not call request', function (done) {
return this.call((err, planCode) => {
this.call((err, planCode) => {
if (err) return done(err)
expect(this.request.callCount).to.equal(0)
return done()
done()
})
})
it('should not error', function (done) {
return this.call(err => {
this.call(err => {
expect(err).to.not.exist
return done()
done()
})
})
})
@ -149,8 +135,8 @@ describe('V1SubscriptionManager', function () {
describe('when the request to v1 fails', function () {
beforeEach(function () {
this.request.yields(new Error('woops'))
return (this.call = cb => {
return this.V1SubscriptionManager._v1Request(
this.call = cb => {
this.V1SubscriptionManager._v1Request(
this.user_id,
{
url() {
@ -159,13 +145,13 @@ describe('V1SubscriptionManager', function () {
},
cb
)
})
}
})
it('should produce an error', function (done) {
return this.call(err => {
this.call(err => {
expect(err).to.exist
return done()
done()
})
})
})
@ -176,8 +162,8 @@ describe('V1SubscriptionManager', function () {
.stub()
.yields(null, this.v1UserId)
this.request.yields(null, { statusCode: 200 }, '{}')
return (this.call = cb => {
return this.V1SubscriptionManager._v1Request(
this.call = cb => {
this.V1SubscriptionManager._v1Request(
this.user_id,
{
method: 'GET',
@ -187,39 +173,42 @@ describe('V1SubscriptionManager', function () {
},
cb
)
})
}
})
it('should not produce an error', function (done) {
return this.call((err, body, v1Id) => {
this.call((err, body, v1Id) => {
expect(err).not.to.exist
return done()
done()
})
})
it('should have supplied retry options to request', function (done) {
return this.call((err, body, v1Id) => {
this.call((err, body, v1Id) => {
if (err) return done(err)
const requestOptions = this.request.lastCall.args[0]
expect(requestOptions.url).to.equal('/foo')
expect(requestOptions.maxAttempts).to.exist
expect(requestOptions.maxAttempts > 0).to.be.true
expect(requestOptions.retryDelay).to.exist
expect(requestOptions.retryDelay > 0).to.be.true
return done()
done()
})
})
it('should return the v1 user id', function (done) {
return this.call((err, body, v1Id) => {
this.call((err, body, v1Id) => {
if (err) return done(err)
expect(v1Id).to.equal(this.v1UserId)
return done()
done()
})
})
it('should return the http response body', function (done) {
return this.call((err, body, v1Id) => {
this.call((err, body, v1Id) => {
if (err) return done(err)
expect(body).to.equal('{}')
return done()
done()
})
})
})
@ -230,8 +219,8 @@ describe('V1SubscriptionManager', function () {
.stub()
.yields(null, this.v1UserId)
this.request.yields(null, { statusCode: 500 }, '{}')
return (this.call = cb => {
return this.V1SubscriptionManager._v1Request(
this.call = cb => {
this.V1SubscriptionManager._v1Request(
this.user_id,
{
url() {
@ -240,13 +229,13 @@ describe('V1SubscriptionManager', function () {
},
cb
)
})
}
})
it('should produce an error', function (done) {
return this.call((err, body, v1Id) => {
this.call((err, body, v1Id) => {
expect(err).to.exist
return done()
done()
})
})
})
@ -257,8 +246,8 @@ describe('V1SubscriptionManager', function () {
.stub()
.yields(null, this.v1UserId)
this.request.yields(null, { statusCode: 404 }, '{}')
return (this.call = cb => {
return this.V1SubscriptionManager._v1Request(
this.call = cb => {
this.V1SubscriptionManager._v1Request(
this.user_id,
{
url() {
@ -267,14 +256,14 @@ describe('V1SubscriptionManager', function () {
},
cb
)
})
}
})
it('should produce an not-found error', function (done) {
return this.call((err, body, v1Id) => {
this.call((err, body, v1Id) => {
expect(err).to.exist
expect(err.name).to.equal('NotFoundError')
return done()
done()
})
})
})
@ -282,21 +271,21 @@ describe('V1SubscriptionManager', function () {
describe('v1IdForUser', function () {
beforeEach(function () {
return (this.UserGetter.getUser = sinon.stub().yields(null, this.user))
this.UserGetter.getUser = sinon.stub().yields(null, this.user)
})
describe('when getUser produces an error', function () {
beforeEach(function () {
this.UserGetter.getUser = sinon.stub().yields(new Error('woops'))
return (this.call = cb => {
return this.V1SubscriptionManager.v1IdForUser(this.user_id, cb)
})
this.call = cb => {
this.V1SubscriptionManager.v1IdForUser(this.user_id, cb)
}
})
it('should produce an error', function (done) {
return this.call(err => {
this.call(err => {
expect(err).to.exist
return done()
done()
})
})
})
@ -304,37 +293,38 @@ describe('V1SubscriptionManager', function () {
describe('when getUser does not find a user', function () {
beforeEach(function () {
this.UserGetter.getUser = sinon.stub().yields(null, null)
return (this.call = cb => {
return this.V1SubscriptionManager.v1IdForUser(this.user_id, cb)
})
this.call = cb => {
this.V1SubscriptionManager.v1IdForUser(this.user_id, cb)
}
})
it('should not error', function (done) {
return this.call((err, user_id) => {
this.call((err, userId) => {
expect(err).to.not.exist
return done()
done()
})
})
})
describe('when it works', function () {
beforeEach(function () {
return (this.call = cb => {
return this.V1SubscriptionManager.v1IdForUser(this.user_id, cb)
})
this.call = cb => {
this.V1SubscriptionManager.v1IdForUser(this.user_id, cb)
}
})
it('should not error', function (done) {
return this.call((err, user_id) => {
this.call((err, userId) => {
expect(err).to.not.exist
return done()
done()
})
})
it('should return the v1 user id', function (done) {
return this.call((err, user_id) => {
expect(user_id).to.eql(42)
return done()
this.call((err, userId) => {
if (err) return done(err)
expect(userId).to.eql(42)
done()
})
})
})