mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
🐛Fix Stripe web hook sub deleted for deleted user
Add check for deleted user in subscription deleted Stripe web hook event handler, and equivalent test case. Add logging for web hook 500 errors to aid future debugging.
This commit is contained in:
parent
9a8da859df
commit
2561bc4caf
2 changed files with 81 additions and 14 deletions
|
@ -11,6 +11,9 @@ module.exports.setup = (app) ->
|
|||
# Cache customer -> user ID map (increases test perf considerably)
|
||||
customerUserMap = {}
|
||||
|
||||
logStripeWebhookError = (msg) ->
|
||||
console.warn "Stripe Webhook Error: #{msg}"
|
||||
|
||||
app.post '/stripe/webhook', (req, res) ->
|
||||
|
||||
# Subscription renewal events:
|
||||
|
@ -102,6 +105,24 @@ module.exports.setup = (app) ->
|
|||
|
||||
subscription = req.body.data.object
|
||||
|
||||
checkUserExists = (done) ->
|
||||
stripe.customers.retrieve subscription.customer, (err, customer) =>
|
||||
if err
|
||||
logStripeWebhookError("Failed to retrieve #{subscription.customer}")
|
||||
return res.send(500, '')
|
||||
unless customer?.metadata?.id
|
||||
logStripeWebhookError("Customer with no metadata.id #{subscription.customer}")
|
||||
return res.send(500, '')
|
||||
User.findById customer.metadata.id, (err, user) =>
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
unless user
|
||||
logStripeWebhookError("User not found #{customer.metadata.id}")
|
||||
return res.send(500, '')
|
||||
return res.send(200, '') if user.get('deleted') is true
|
||||
done()
|
||||
|
||||
checkNormalSubscription = (done) ->
|
||||
User.findOne {'stripe.subscriptionID': subscription.id}, (err, user) ->
|
||||
return done() unless user
|
||||
|
@ -112,17 +133,28 @@ module.exports.setup = (app) ->
|
|||
delete stripeInfo.subscriptionID
|
||||
user.set('stripe', stripeInfo)
|
||||
user.save (err) =>
|
||||
return res.send(500, '') if err
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
return res.send(200, '')
|
||||
|
||||
checkRecipientSubscription = (done) ->
|
||||
return done() unless subscription.plan.id is 'basic'
|
||||
return done() unless subscription.metadata?.id # Shouldn't be possible
|
||||
User.findById subscription.metadata.id, (err, recipient) =>
|
||||
return res.send(500, '') if err
|
||||
return res.send(500, '') unless recipient
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
unless recipient
|
||||
logStripeWebhookError("Recipient not found #{subscription.metadata.id}")
|
||||
return res.send(500, '')
|
||||
User.findById recipient.get('stripe').sponsorID, (err, sponsor) =>
|
||||
return res.send(500, '') if err
|
||||
return res.send(500, '') unless sponsor
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
unless sponsor
|
||||
logStripeWebhookError("Sponsor not found #{recipient.get('stripe').sponsorID}")
|
||||
return res.send(500, '')
|
||||
|
||||
# Update sponsor subscription
|
||||
stripeInfo = _.cloneDeep(sponsor.get('stripe') ? {})
|
||||
|
@ -130,12 +162,16 @@ module.exports.setup = (app) ->
|
|||
options =
|
||||
quantity: utils.getSponsoredSubsAmount(subscription.plan.amount, stripeInfo.recipients.length, stripeInfo.subscriptionID?)
|
||||
stripe.customers.updateSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, options, (err, subscription) =>
|
||||
return res.send(500, '') if err
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
|
||||
# Update sponsor user
|
||||
sponsor.set 'stripe', stripeInfo
|
||||
sponsor.save (err) =>
|
||||
return res.send(500, '') if err
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
|
||||
# Update recipient user
|
||||
stripeInfo = recipient.get('stripe')
|
||||
|
@ -145,7 +181,9 @@ module.exports.setup = (app) ->
|
|||
else
|
||||
recipient.set 'stripe', stripeInfo
|
||||
recipient.save (err) =>
|
||||
return res.send(500, '') if err
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
return res.send(200, '')
|
||||
|
||||
checkSponsorSubscription = (done) ->
|
||||
|
@ -165,7 +203,9 @@ module.exports.setup = (app) ->
|
|||
|
||||
# Cancel all recipient subscriptions
|
||||
async.parallel (createUpdateFn(sub) for sub in stripeInfo.recipients), (err, results) =>
|
||||
return res.send(500, '') if err
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
|
||||
# Update sponsor user
|
||||
delete stripeInfo.sponsorSubscriptionID
|
||||
|
@ -175,10 +215,13 @@ module.exports.setup = (app) ->
|
|||
else
|
||||
sponsor.set 'stripe', stripeInfo
|
||||
sponsor.save (err) =>
|
||||
return res.send(500, '') if err
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
done()
|
||||
|
||||
# TODO: use async.series for this
|
||||
checkUserExists ->
|
||||
checkNormalSubscription ->
|
||||
checkRecipientSubscription ->
|
||||
checkSponsorSubscription ->
|
||||
|
|
|
@ -681,6 +681,30 @@ describe 'Subscriptions', ->
|
|||
expect(stripeInfo.subscriptionID).toBeUndefined()
|
||||
done()
|
||||
|
||||
it 'User subscribes, deletes themselves, subscription ends', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginNewUser (user1) ->
|
||||
# Subscribe user
|
||||
subscribeUser user1, token, null, ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
customerID = user1.get('stripe').customerID
|
||||
subscriptionID = user1.get('stripe').subscriptionID
|
||||
stripe.customers.retrieveSubscription customerID, subscriptionID, (err, subscription) ->
|
||||
expect(err).toBeNull()
|
||||
expect(subscription).not.toBeNull()
|
||||
# Delete user
|
||||
request.del {uri: "#{userURL}/#{user1.id}"}, (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
# Simulate Stripe subscription deleted via webhook
|
||||
event = _.cloneDeep(customerSubscriptionDeletedSampleEvent)
|
||||
event.data.object = subscription
|
||||
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200)
|
||||
done()
|
||||
|
||||
describe 'Sponsored', ->
|
||||
it 'Unsubscribed user1 subscribes user2', (done) ->
|
||||
|
|
Loading…
Reference in a new issue