mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #2454 from overleaf/ta-recurly-address-check
Check Country Presence when Creating New Subscription GitOrigin-RevId: a92266cf2a304e3649ff3b02f9b47e76ae0f8523
This commit is contained in:
parent
3f669510e5
commit
390c8641da
4 changed files with 81 additions and 32 deletions
|
@ -24,6 +24,7 @@ const Settings = require('settings-sharelatex')
|
||||||
const xml2js = require('xml2js')
|
const xml2js = require('xml2js')
|
||||||
const logger = require('logger-sharelatex')
|
const logger = require('logger-sharelatex')
|
||||||
const Async = require('async')
|
const Async = require('async')
|
||||||
|
const Errors = require('../Errors/Errors')
|
||||||
const SubscriptionErrors = require('./Errors')
|
const SubscriptionErrors = require('./Errors')
|
||||||
|
|
||||||
module.exports = RecurlyWrapper = {
|
module.exports = RecurlyWrapper = {
|
||||||
|
@ -79,28 +80,22 @@ module.exports = RecurlyWrapper = {
|
||||||
createAccount(cache, next) {
|
createAccount(cache, next) {
|
||||||
const { user } = cache
|
const { user } = cache
|
||||||
const { subscriptionDetails } = cache
|
const { subscriptionDetails } = cache
|
||||||
const { address } = subscriptionDetails
|
|
||||||
if (!address) {
|
|
||||||
return next(
|
|
||||||
new Error('no address in subscriptionDetails at createAccount stage')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (cache.userExists) {
|
if (cache.userExists) {
|
||||||
return next(null, cache)
|
return next(null, cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let address
|
||||||
|
try {
|
||||||
|
address = getAddressFromSubscriptionDetails(subscriptionDetails)
|
||||||
|
} catch (error) {
|
||||||
|
return next(error)
|
||||||
|
}
|
||||||
const data = {
|
const data = {
|
||||||
account_code: user._id,
|
account_code: user._id,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
first_name: user.first_name,
|
first_name: user.first_name,
|
||||||
last_name: user.last_name,
|
last_name: user.last_name,
|
||||||
address: {
|
address
|
||||||
address1: address.address1,
|
|
||||||
address2: address.address2 || '',
|
|
||||||
city: address.city || '',
|
|
||||||
state: address.state || '',
|
|
||||||
zip: address.zip || '',
|
|
||||||
country: address.country
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const requestBody = RecurlyWrapper._buildXml('account', data)
|
const requestBody = RecurlyWrapper._buildXml('account', data)
|
||||||
|
|
||||||
|
@ -189,21 +184,14 @@ module.exports = RecurlyWrapper = {
|
||||||
if (!accountCode) {
|
if (!accountCode) {
|
||||||
return next(new Error('no account code at setAddress stage'))
|
return next(new Error('no account code at setAddress stage'))
|
||||||
}
|
}
|
||||||
const { address } = subscriptionDetails
|
|
||||||
if (!address) {
|
let address
|
||||||
return next(
|
try {
|
||||||
new Error('no address in subscriptionDetails at setAddress stage')
|
address = getAddressFromSubscriptionDetails(subscriptionDetails)
|
||||||
)
|
} catch (error) {
|
||||||
|
return next(error)
|
||||||
}
|
}
|
||||||
const data = {
|
const requestBody = RecurlyWrapper._buildXml('billing_info', address)
|
||||||
address1: address.address1,
|
|
||||||
address2: address.address2 || '',
|
|
||||||
city: address.city || '',
|
|
||||||
state: address.state || '',
|
|
||||||
zip: address.zip || '',
|
|
||||||
country: address.country
|
|
||||||
}
|
|
||||||
const requestBody = RecurlyWrapper._buildXml('billing_info', data)
|
|
||||||
|
|
||||||
return RecurlyWrapper.apiRequest(
|
return RecurlyWrapper.apiRequest(
|
||||||
{
|
{
|
||||||
|
@ -1051,6 +1039,31 @@ function getCustomFieldsFromSubscriptionDetails(subscriptionDetails) {
|
||||||
return { custom_field: customFields }
|
return { custom_field: customFields }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAddressFromSubscriptionDetails(subscriptionDetails) {
|
||||||
|
const { address } = subscriptionDetails
|
||||||
|
if (!address || !address.country) {
|
||||||
|
throw new Errors.InvalidError({
|
||||||
|
message: 'Invalid country',
|
||||||
|
info: {
|
||||||
|
public: {
|
||||||
|
message: 'Invalid country'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const addressObject = {
|
||||||
|
address1: address.address1,
|
||||||
|
address2: address.address2 || '',
|
||||||
|
city: address.city || '',
|
||||||
|
state: address.state || '',
|
||||||
|
zip: address.zip || '',
|
||||||
|
country: address.country
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressObject
|
||||||
|
}
|
||||||
|
|
||||||
function __guard__(value, transform) {
|
function __guard__(value, transform) {
|
||||||
return typeof value !== 'undefined' && value !== null
|
return typeof value !== 'undefined' && value !== null
|
||||||
? transform(value)
|
? transform(value)
|
||||||
|
|
|
@ -29,6 +29,7 @@ const FeaturesUpdater = require('./FeaturesUpdater')
|
||||||
const planFeatures = require('./planFeatures')
|
const planFeatures = require('./planFeatures')
|
||||||
const GroupPlansData = require('./GroupPlansData')
|
const GroupPlansData = require('./GroupPlansData')
|
||||||
const V1SubscriptionManager = require('./V1SubscriptionManager')
|
const V1SubscriptionManager = require('./V1SubscriptionManager')
|
||||||
|
const Errors = require('../Errors/Errors')
|
||||||
const SubscriptionErrors = require('./Errors')
|
const SubscriptionErrors = require('./Errors')
|
||||||
const HttpErrors = require('@overleaf/o-error/http')
|
const HttpErrors = require('@overleaf/o-error/http')
|
||||||
|
|
||||||
|
@ -219,6 +220,10 @@ module.exports = SubscriptionController = {
|
||||||
return next(
|
return next(
|
||||||
new HttpErrors.UnprocessableEntityError({}).withCause(err)
|
new HttpErrors.UnprocessableEntityError({}).withCause(err)
|
||||||
)
|
)
|
||||||
|
} else if (err instanceof Errors.InvalidError) {
|
||||||
|
return next(
|
||||||
|
new HttpErrors.UnprocessableEntityError({}).withCause(err)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.warn(
|
logger.warn(
|
||||||
|
|
|
@ -21,6 +21,7 @@ const querystring = require('querystring')
|
||||||
const modulePath = '../../../../app/src/Features/Subscription/RecurlyWrapper'
|
const modulePath = '../../../../app/src/Features/Subscription/RecurlyWrapper'
|
||||||
const SandboxedModule = require('sandboxed-module')
|
const SandboxedModule = require('sandboxed-module')
|
||||||
const tk = require('timekeeper')
|
const tk = require('timekeeper')
|
||||||
|
const Errors = require('../../../../app/src/Features/Errors/Errors')
|
||||||
const SubscriptionErrors = require('../../../../app/src/Features/Subscription/Errors')
|
const SubscriptionErrors = require('../../../../app/src/Features/Subscription/Errors')
|
||||||
|
|
||||||
const fixtures = {
|
const fixtures = {
|
||||||
|
@ -158,7 +159,8 @@ describe('RecurlyWrapper', function() {
|
||||||
},
|
},
|
||||||
request: sinon.stub(),
|
request: sinon.stub(),
|
||||||
xml2js: require('xml2js'),
|
xml2js: require('xml2js'),
|
||||||
'./Errors': SubscriptionErrors
|
'./Errors': SubscriptionErrors,
|
||||||
|
'../Errors/Errors': Errors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
@ -1148,6 +1150,19 @@ describe('RecurlyWrapper', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when country is missing from address', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
return (this.cache.subscriptionDetails.address = {})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should produce an error', function(done) {
|
||||||
|
return this.call((err, result) => {
|
||||||
|
expect(err).to.be.instanceof(Errors.InvalidError)
|
||||||
|
return done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('when account already exists', function() {
|
describe('when account already exists', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.cache.userExists = true
|
this.cache.userExists = true
|
||||||
|
@ -1378,14 +1393,14 @@ describe('RecurlyWrapper', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('when address is missing from subscriptionDetails', function() {
|
describe('when country is missing', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
return (this.cache.subscriptionDetails.address = null)
|
return (this.cache.subscriptionDetails.address = { country: '' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should produce an error', function(done) {
|
it('should produce an error', function(done) {
|
||||||
return this.call((err, result) => {
|
return this.call((err, result) => {
|
||||||
expect(err).to.be.instanceof(Error)
|
expect(err).to.be.instanceof(Errors.InvalidError)
|
||||||
return done()
|
return done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,6 +19,7 @@ const MockRequest = require('../helpers/MockRequest')
|
||||||
const MockResponse = require('../helpers/MockResponse')
|
const MockResponse = require('../helpers/MockResponse')
|
||||||
const modulePath =
|
const modulePath =
|
||||||
'../../../../app/src/Features/Subscription/SubscriptionController'
|
'../../../../app/src/Features/Subscription/SubscriptionController'
|
||||||
|
const Errors = require('../../../../app/src/Features/Errors/Errors')
|
||||||
const SubscriptionErrors = require('../../../../app/src/Features/Subscription/Errors')
|
const SubscriptionErrors = require('../../../../app/src/Features/Subscription/Errors')
|
||||||
const OError = require('@overleaf/o-error')
|
const OError = require('@overleaf/o-error')
|
||||||
const HttpErrors = require('@overleaf/o-error/http')
|
const HttpErrors = require('@overleaf/o-error/http')
|
||||||
|
@ -118,6 +119,7 @@ describe('SubscriptionController', function() {
|
||||||
'./FeaturesUpdater': (this.FeaturesUpdater = {}),
|
'./FeaturesUpdater': (this.FeaturesUpdater = {}),
|
||||||
'./GroupPlansData': (this.GroupPlansData = {}),
|
'./GroupPlansData': (this.GroupPlansData = {}),
|
||||||
'./V1SubscriptionManager': (this.V1SubscriptionManager = {}),
|
'./V1SubscriptionManager': (this.V1SubscriptionManager = {}),
|
||||||
|
'../Errors/Errors': Errors,
|
||||||
'./Errors': SubscriptionErrors,
|
'./Errors': SubscriptionErrors,
|
||||||
'@overleaf/o-error/http': HttpErrors
|
'@overleaf/o-error/http': HttpErrors
|
||||||
}
|
}
|
||||||
|
@ -433,6 +435,20 @@ describe('SubscriptionController', function() {
|
||||||
})
|
})
|
||||||
return done()
|
return done()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should handle validation errors', function(done) {
|
||||||
|
this.next = sinon.stub()
|
||||||
|
this.LimitationsManager.userHasV1OrV2Subscription.yields(null, false)
|
||||||
|
this.SubscriptionHandler.createSubscription.yields(
|
||||||
|
new Errors.InvalidError({})
|
||||||
|
)
|
||||||
|
this.SubscriptionController.createSubscription(this.req, null, error => {
|
||||||
|
expect(error).to.exist
|
||||||
|
expect(error).to.be.instanceof(HttpErrors.UnprocessableEntityError)
|
||||||
|
expect(OError.hasCauseInstanceOf(error, Errors.InvalidError)).to.be.true
|
||||||
|
})
|
||||||
|
return done()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('updateSubscription via post', function() {
|
describe('updateSubscription via post', function() {
|
||||||
|
|
Loading…
Reference in a new issue