mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Cancel recipient subscriptions immediately
This commit is contained in:
parent
593f7a9dd7
commit
5c240d89cd
3 changed files with 62 additions and 40 deletions
|
@ -582,18 +582,26 @@ class SubscriptionHandler extends Handler
|
|||
email = req.body.stripe.unsubscribeEmail.trim().toLowerCase()
|
||||
return done({res: 'Database error.', code: 500}) if _.isEmpty(email)
|
||||
|
||||
deleteUserStripeProp = (user, propName) ->
|
||||
stripeInfo = _.cloneDeep(user.get('stripe') ? {})
|
||||
delete stripeInfo[propName]
|
||||
if _.isEmpty stripeInfo
|
||||
user.set 'stripe', undefined
|
||||
else
|
||||
user.set 'stripe', stripeInfo
|
||||
|
||||
User.findOne {emailLower: email}, (err, recipient) =>
|
||||
if err
|
||||
@logSubscriptionError(user, "User lookup error. " + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
unless recipient
|
||||
@logSubscriptionError(user, "Recipient #{req.body.stripe.recipient} not found. " + err)
|
||||
@logSubscriptionError(user, "Recipient #{email} not found.")
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
# Check recipient is currently sponsored
|
||||
stripeRecipient = recipient.get 'stripe' ? {}
|
||||
if stripeRecipient?.sponsorID isnt user.id
|
||||
@logSubscriptionError(user, "Recipient #{req.body.stripe.recipient} not found. " + err)
|
||||
@logSubscriptionError(user, "Recipient #{req.body.stripe.recipient} not found. ")
|
||||
return done({res: 'Can only unsubscribe sponsored subscriptions.', code: 403})
|
||||
|
||||
# Find recipient subscription
|
||||
|
@ -603,22 +611,41 @@ class SubscriptionHandler extends Handler
|
|||
sponsoredEntry = sponsored
|
||||
break
|
||||
unless sponsoredEntry?
|
||||
@logSubscriptionError(user, 'Unable to find sponsored subscription. ' + err)
|
||||
@logSubscriptionError(user, 'Unable to find recipient subscription. ')
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
# Cancel Stripe subscription
|
||||
stripe.customers.cancelSubscription stripeInfo.customerID, sponsoredEntry.subscriptionID, { at_period_end: true }, (err) =>
|
||||
if err or not recipient
|
||||
@logSubscriptionError(user, "Stripe cancel sponsored subscription failed. " + err)
|
||||
# Update recipient user
|
||||
deleteUserStripeProp(recipient, 'sponsorID')
|
||||
recipient.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Recipient user save unsubscribe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
delete stripeInfo.unsubscribeEmail
|
||||
user.set('stripe', stripeInfo)
|
||||
req.body.stripe = stripeInfo
|
||||
user.save (err) =>
|
||||
# Cancel Stripe subscription
|
||||
stripe.customers.cancelSubscription stripeInfo.customerID, sponsoredEntry.subscriptionID, (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'User save unsubscribe error. ' + err)
|
||||
@logSubscriptionError(user, "Stripe cancel sponsored subscription failed. " + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
|
||||
# Update sponsor user
|
||||
_.remove(stripeInfo.recipients, (s) -> s.userID is recipient.id)
|
||||
delete stripeInfo.unsubscribeEmail
|
||||
user.set('stripe', stripeInfo)
|
||||
req.body.stripe = stripeInfo
|
||||
user.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Sponsor user save unsubscribe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
return done() unless stripeInfo.sponsorSubscriptionID?
|
||||
|
||||
# Update sponsored subscription quantity
|
||||
options =
|
||||
quantity: getSponsoredSubsAmount(subscriptions.basic.amount, stripeInfo.recipients.length, stripeInfo.subscriptionID?)
|
||||
stripe.customers.updateSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, options, (err, subscription) =>
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
return res.send(500, '')
|
||||
done()
|
||||
|
||||
module.exports = new SubscriptionHandler()
|
||||
|
|
|
@ -157,6 +157,10 @@ module.exports.setup = (app) ->
|
|||
unless recipient
|
||||
logStripeWebhookError("Recipient not found #{subscription.metadata.id}")
|
||||
return res.send(500, '')
|
||||
|
||||
# Recipient cancellations are immediate, no work to perform if recipient's sponsorID is already gone
|
||||
return res.send(200, '') unless recipient.get('stripe')?.sponsorID?
|
||||
|
||||
User.findById recipient.get('stripe').sponsorID, (err, sponsor) =>
|
||||
if err
|
||||
logStripeWebhookError(err)
|
||||
|
|
|
@ -259,6 +259,8 @@ describe 'Subscriptions', ->
|
|||
# console.log 'verifyNotSponsoring', sponsorID, recipientID
|
||||
User.findById sponsorID, (err, sponsor) ->
|
||||
expect(err).toBeNull()
|
||||
expect(sponsor).not.toBeNull()
|
||||
return done() unless sponsor
|
||||
stripeInfo = sponsor.get('stripe')
|
||||
return done() unless stripeInfo?.customerID?
|
||||
checkSubscriptions = (starting_after, done) ->
|
||||
|
@ -282,6 +284,7 @@ describe 'Subscriptions', ->
|
|||
User.findById sponsorUserID, (err, user) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user).not.toBeNull()
|
||||
return done() unless user
|
||||
sponsorStripe = user.get('stripe')
|
||||
sponsorCustomerID = sponsorStripe.customerID
|
||||
numSponsored = sponsorStripe.recipients?.length
|
||||
|
@ -443,7 +446,7 @@ describe 'Subscriptions', ->
|
|||
expect(err?).toEqual(false)
|
||||
done(updatedUser)
|
||||
|
||||
unsubscribeRecipient = (sponsor, recipient, immediately, done) ->
|
||||
unsubscribeRecipient = (sponsor, recipient, done) ->
|
||||
# console.log 'unsubscribeRecipient', sponsor.id, recipient.id
|
||||
stripeInfo = sponsor.get('stripe')
|
||||
customerID = stripeInfo.customerID
|
||||
|
@ -467,20 +470,7 @@ describe 'Subscriptions', ->
|
|||
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
|
||||
# Simulate subscription ending after cancellation
|
||||
return done() unless immediately
|
||||
|
||||
# Simulate subscription cancelling at period end
|
||||
stripe.customers.cancelSubscription customerID, subscriptionID, (err) ->
|
||||
expect(err).toBeNull()
|
||||
|
||||
# Simulate customer.subscription.deleted webhook event
|
||||
event = _.cloneDeep(customerSubscriptionDeletedSampleEvent)
|
||||
event.data.object = subscription
|
||||
request.post {uri: webhookURL, json: event}, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
done()
|
||||
done()
|
||||
|
||||
# Subscribe a bunch of recipients at once, used for bulk discount testing
|
||||
class SubbedRecipients
|
||||
|
@ -762,11 +752,11 @@ describe 'Subscriptions', ->
|
|||
expect(err).toBeNull()
|
||||
|
||||
User.findById user1.id, (err, user1) ->
|
||||
unsubscribeRecipient user1, user2, true, ->
|
||||
unsubscribeRecipient user1, user2, ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.get('stripe').subscriptionID).toBeDefined()
|
||||
expect(user1.get('stripe').recipients).toBeUndefined()
|
||||
expect(_.isEmpty(user1.get('stripe').recipients)).toEqual(true)
|
||||
expect(user1.isPremium()).toEqual(true)
|
||||
User.findById user2.id, (err, user2) ->
|
||||
verifyNotSponsoring user1.id, user2.id, ->
|
||||
|
@ -781,7 +771,7 @@ describe 'Subscriptions', ->
|
|||
loginNewUser (user1) ->
|
||||
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
unsubscribeRecipient user1, user2, true, ->
|
||||
unsubscribeRecipient user1, user2, ->
|
||||
verifyNotSponsoring user1.id, user2.id, ->
|
||||
verifyNotRecipient user2.id, done
|
||||
|
||||
|
@ -793,7 +783,7 @@ describe 'Subscriptions', ->
|
|||
loginNewUser (user1) ->
|
||||
subscribeRecipients user1, [user2], token, (updatedUser) ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
unsubscribeRecipient user1, user2, false, ->
|
||||
unsubscribeRecipient user1, user2, ->
|
||||
subscribeRecipients user1, [user2], null, (updatedUser) ->
|
||||
verifySponsorship user1.id, user2.id, done
|
||||
|
||||
|
@ -846,7 +836,7 @@ describe 'Subscriptions', ->
|
|||
expect(err).toBeNull()
|
||||
subscribeRecipients user1, [user2], null, (updatedUser) ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
unsubscribeRecipient user1, user2, true, ->
|
||||
unsubscribeRecipient user1, user2, ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.get('stripe').subscriptionID).toBeDefined()
|
||||
|
@ -1138,7 +1128,7 @@ describe 'Subscriptions', ->
|
|||
User.findById user1.id, (err, user1) ->
|
||||
|
||||
# Unsubscribe recipient0
|
||||
unsubscribeRecipient user1, recipients.get(0), true, ->
|
||||
unsubscribeRecipient user1, recipients.get(0), ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
stripeInfo = user1.get('stripe')
|
||||
expect(stripeInfo.recipients.length).toEqual(1)
|
||||
|
@ -1150,7 +1140,7 @@ describe 'Subscriptions', ->
|
|||
expect(subscription.quantity).toEqual(getSubscribedQuantity(1))
|
||||
|
||||
# Unsubscribe recipient1
|
||||
unsubscribeRecipient user1, recipients.get(1), true, ->
|
||||
unsubscribeRecipient user1, recipients.get(1), ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
stripeInfo = user1.get('stripe')
|
||||
expect(stripeInfo.recipients.length).toEqual(0)
|
||||
|
@ -1186,7 +1176,7 @@ describe 'Subscriptions', ->
|
|||
User.findById user1.id, (err, user1) ->
|
||||
|
||||
# Unsubscribe first recipient
|
||||
unsubscribeRecipient user1, recipients.get(0), true, ->
|
||||
unsubscribeRecipient user1, recipients.get(0), ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
stripeInfo = user1.get('stripe')
|
||||
expect(stripeInfo.recipients.length).toEqual(recipientCount - 1)
|
||||
|
@ -1198,7 +1188,7 @@ describe 'Subscriptions', ->
|
|||
expect(subscription.quantity).toEqual(getSubscribedQuantity(recipientCount - 1))
|
||||
|
||||
# Unsubscribe second recipient
|
||||
unsubscribeRecipient user1, recipients.get(1), true, ->
|
||||
unsubscribeRecipient user1, recipients.get(1), ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
stripeInfo = user1.get('stripe')
|
||||
expect(stripeInfo.recipients.length).toEqual(recipientCount - 2)
|
||||
|
@ -1218,7 +1208,7 @@ describe 'Subscriptions', ->
|
|||
|
||||
# Unsubscribe third recipient
|
||||
verifySponsorship user1.id, recipients.get(2).id, ->
|
||||
unsubscribeRecipient user1, recipients.get(2), true, ->
|
||||
unsubscribeRecipient user1, recipients.get(2), ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
stripeInfo = user1.get('stripe')
|
||||
expect(stripeInfo.recipients.length).toEqual(recipientCount - 3)
|
||||
|
@ -1252,8 +1242,9 @@ describe 'Subscriptions', ->
|
|||
User.findById user1.id, (err, user1) ->
|
||||
|
||||
# Unsubscribe first recipient
|
||||
unsubscribeRecipient user1, recipients.get(0), true, ->
|
||||
unsubscribeRecipient user1, recipients.get(0), ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
|
||||
stripeInfo = user1.get('stripe')
|
||||
expect(stripeInfo.recipients.length).toEqual(recipientCount - 1)
|
||||
verifyNotSponsoring user1.id, recipients.get(0).id, ->
|
||||
|
@ -1264,7 +1255,7 @@ describe 'Subscriptions', ->
|
|||
expect(subscription.quantity).toEqual(getUnsubscribedQuantity(recipientCount - 1))
|
||||
|
||||
# Unsubscribe last recipient
|
||||
unsubscribeRecipient user1, recipients.get(recipientCount - 1), true, ->
|
||||
unsubscribeRecipient user1, recipients.get(recipientCount - 1), ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
stripeInfo = user1.get('stripe')
|
||||
expect(stripeInfo.recipients.length).toEqual(recipientCount - 2)
|
||||
|
|
Loading…
Reference in a new issue