mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Update prepaids to support multiple redeemers for a single code
Will remove deprecated properties after updating production.
This commit is contained in:
parent
49dc71a157
commit
9c39bf7656
9 changed files with 144 additions and 58 deletions
|
@ -1,12 +1,15 @@
|
|||
c = require './../schemas'
|
||||
|
||||
PrepaidSchema = c.object({title: 'Prepaid', required: ['creator', 'redeemer', 'type']}, {
|
||||
PrepaidSchema = c.object({title: 'Prepaid', required: ['creator', 'type']}, {
|
||||
creator: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ])
|
||||
redeemer: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ])
|
||||
redeemers: c.array {}, c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ])
|
||||
maxRedeemers: { type: 'integer'}
|
||||
code: c.shortString(title: "Unique code to redeem")
|
||||
type: { type: 'string' }
|
||||
status: { enum: ['active', 'used'], default: 'active' }
|
||||
properties: {type: 'object'}
|
||||
# Deprecated
|
||||
status: { enum: ['active', 'used'], default: 'active' }
|
||||
redeemer: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ])
|
||||
})
|
||||
|
||||
c.extendBasicProperties(PrepaidSchema, 'prepaid')
|
||||
|
|
|
@ -77,7 +77,7 @@ module.exports = class MainAdminView extends RootView
|
|||
return unless me.isAdmin()
|
||||
options =
|
||||
url: '/db/prepaid/-/create'
|
||||
data: {type: 'subscription'}
|
||||
data: {type: 'subscription', maxRedeemers: 1}
|
||||
method: 'POST'
|
||||
options.success = (model, response, options) =>
|
||||
# TODO: Don't hardcode domain.
|
||||
|
|
|
@ -22,7 +22,7 @@ function createPrepaid()
|
|||
criteria = {
|
||||
creator: creatorID,
|
||||
type: 'subscription',
|
||||
status: 'active',
|
||||
maxRedeemers: 1
|
||||
code: code,
|
||||
properties: {
|
||||
couponID: 'free'
|
||||
|
|
|
@ -174,16 +174,51 @@ class SubscriptionHandler extends Handler
|
|||
return done({res: 'Database error.', code: 500})
|
||||
return done({res: 'Prepaid not found', code: 404}) unless prepaid?
|
||||
return done({res: 'Prepaid not for subscription', code: 403}) unless prepaid.get('type') is 'subscription'
|
||||
return done({res: 'Prepaid has already been used', code: 403}) unless prepaid.get('status') is 'active'
|
||||
return done({res: 'Database error.', code: 500}) unless prepaid.get('properties')?.couponID
|
||||
couponID = prepaid.get('properties').couponID
|
||||
|
||||
# Update user
|
||||
stripeInfo = _.cloneDeep(user.get('stripe') ? {})
|
||||
stripeInfo.couponID = couponID
|
||||
stripeInfo.prepaidCode = req.body.stripe.prepaidCode
|
||||
user.set('stripe', stripeInfo)
|
||||
@checkForExistingSubscription(req, user, customer, couponID, done)
|
||||
# Deprecated: status property
|
||||
if status = prepaid.get('status') and status is 'used'
|
||||
return done({res: 'Prepaid has already been used', code: 403})
|
||||
|
||||
if prepaid.get('redeemers')?.length >= prepaid.get('maxRedeemers')
|
||||
@logSubscriptionError(user, "Prepaid #{prepaid.id} note active")
|
||||
return done({res: 'Prepaid not active', code: 403})
|
||||
unless couponID = prepaid.get('properties')?.couponID
|
||||
@logSubscriptionError(user, "Prepaid #{prepaid.id} has no couponID")
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
redeemers = prepaid.get('redeemers') ? []
|
||||
if _.find(redeemers, (a) -> a.userID?.equals(user.get('_id')))
|
||||
@logSubscriptionError(user, "Prepaid code already redeemed by #{user.id}")
|
||||
return done({res: 'Prepaid code already redeemed', code: 403})
|
||||
|
||||
# Redeem prepaid code
|
||||
|
||||
# Deprecated: status and redeemer properties
|
||||
prepaid.set('status', 'used')
|
||||
prepaid.set('redeemer', user.get('_id'))
|
||||
|
||||
query = Prepaid.$where("'#{prepaid.get('_id').valueOf()}' === this._id.valueOf() && (!this.redeemers || this.redeemers.length < this.maxRedeemers)")
|
||||
redeemers.push
|
||||
userID: user.get('_id')
|
||||
date: new Date()
|
||||
update = {redeemers: redeemers}
|
||||
Prepaid.update query, update, {}, (err, numAffected) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Prepaid update error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
if numAffected > 1
|
||||
@logSubscriptionError(user, "Prepaid numAffected=#{numAffected} error.")
|
||||
return done({res: 'Database error.', code: 500})
|
||||
if numAffected < 1
|
||||
return done({res: 'Prepaid not active', code: 403})
|
||||
|
||||
# Update user
|
||||
stripeInfo = _.cloneDeep(user.get('stripe') ? {})
|
||||
stripeInfo.couponID = couponID
|
||||
stripeInfo.prepaidCode = req.body.stripe.prepaidCode
|
||||
user.set('stripe', stripeInfo)
|
||||
@checkForExistingSubscription(req, user, customer, couponID, done)
|
||||
|
||||
else
|
||||
couponID = user.get('stripe')?.couponID
|
||||
# SALE LOGIC
|
||||
|
@ -257,25 +292,7 @@ class SubscriptionHandler extends Handler
|
|||
if err
|
||||
@logSubscriptionError(user, 'Stripe user plan saving error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
if stripeInfo.prepaidCode?
|
||||
# Update prepaid to 'used'
|
||||
Prepaid.findOne code: stripeInfo.prepaidCode, (err, prepaid) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Prepaid find error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
unless prepaid?
|
||||
@logSubscriptionError(user, "Expected prepaid not found: #{stripeInfo.prepaidCode}")
|
||||
return done({res: 'Database error.', code: 500})
|
||||
prepaid.set('status', 'used')
|
||||
prepaid.set('redeemer', user.get('_id'))
|
||||
prepaid.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Prepaid update error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
else
|
||||
done()
|
||||
done()
|
||||
|
||||
updateStripeRecipientSubscriptions: (req, user, customer, done) ->
|
||||
return done({res: 'Database error.', code: 500}) unless req.body.stripe?.subscribeEmails?
|
||||
|
|
|
@ -20,13 +20,14 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
createPrepaid: (req, res) ->
|
||||
return @sendForbiddenError(res) unless @hasAccess(req)
|
||||
return @sendForbiddenError(res) unless req.body.type is 'subscription'
|
||||
return @sendForbiddenError(res) unless req.body.maxRedeemers > 0
|
||||
Prepaid.generateNewCode (code) =>
|
||||
return @sendDatabaseError(res, 'Database error.') unless code
|
||||
prepaid = new Prepaid
|
||||
creator: req.user.id
|
||||
type: req.body.type
|
||||
status: 'active'
|
||||
code: code
|
||||
maxRedeemers: req.body.maxRedeemers
|
||||
properties:
|
||||
couponID: 'free'
|
||||
prepaid.save (err) =>
|
||||
|
|
|
@ -17,7 +17,7 @@ TrialRequestSchema.pre 'save', (next) ->
|
|||
prepaid = new Prepaid
|
||||
creator: @get('reviewer')
|
||||
type: 'subscription'
|
||||
status: 'active'
|
||||
maxRedeemers: 1
|
||||
code: code
|
||||
properties:
|
||||
couponID: 'free'
|
||||
|
|
|
@ -118,9 +118,11 @@ wrapUpGetUser = (email, user, done) ->
|
|||
GLOBAL.getURL = (path) ->
|
||||
return 'http://localhost:3001' + path
|
||||
|
||||
GLOBAL.createPrepaid = (type, done) ->
|
||||
GLOBAL.createPrepaid = (type, maxRedeemers, done) ->
|
||||
options = uri: GLOBAL.getURL('/db/prepaid/-/create')
|
||||
options.json = type: type if type?
|
||||
options.json =
|
||||
type: type
|
||||
maxRedeemers: maxRedeemers
|
||||
request.post options, done
|
||||
|
||||
newUserCount = 0
|
||||
|
|
|
@ -7,7 +7,7 @@ describe '/db/prepaid', ->
|
|||
verifyPrepaid = (user, prepaid, done) ->
|
||||
expect(prepaid.creator).toEqual(user.id)
|
||||
expect(prepaid.type).toEqual('subscription')
|
||||
expect(prepaid.status).toEqual('active')
|
||||
expect(prepaid.maxRedeemers).toBeGreaterThan(0)
|
||||
expect(prepaid.code).toMatch(/^\w{8}$/)
|
||||
expect(prepaid.properties?.couponID).toEqual('free')
|
||||
done()
|
||||
|
@ -18,7 +18,7 @@ describe '/db/prepaid', ->
|
|||
done()
|
||||
|
||||
it 'Anonymous creates prepaid code', (done) ->
|
||||
createPrepaid 'subscription', (err, res, body) ->
|
||||
createPrepaid 'subscription', 1, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(401)
|
||||
done()
|
||||
|
@ -26,7 +26,7 @@ describe '/db/prepaid', ->
|
|||
it 'Non-admin creates prepaid code', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
expect(user1.isAdmin()).toEqual(false)
|
||||
createPrepaid 'subscription', (err, res, body) ->
|
||||
createPrepaid 'subscription', 4, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
@ -37,7 +37,7 @@ describe '/db/prepaid', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, body) ->
|
||||
createPrepaid 'subscription', 1, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
verifyPrepaid user1, body, done
|
||||
|
@ -48,7 +48,7 @@ describe '/db/prepaid', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'bulldozer', (err, res, body) ->
|
||||
createPrepaid 'bulldozer', 1, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
@ -59,7 +59,18 @@ describe '/db/prepaid', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid null, (err, res, body) ->
|
||||
createPrepaid null, 1, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'Admin creates prepaid code with invalid maxRedeemers', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
user1.set('permissions', ['admin'])
|
||||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', 0, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
@ -78,7 +89,7 @@ describe '/db/prepaid', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
request.get {uri: prepaidURL}, (err, res, body) ->
|
||||
|
|
|
@ -542,14 +542,38 @@ describe 'Subscriptions', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('status')).toEqual('used')
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
||||
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
||||
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
||||
done()
|
||||
|
||||
it 'Admin subscribes self with valid prepaid twice', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
user1.set('permissions', ['admin'])
|
||||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', 2, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
prepaid.set 'redeemers', [{userID: user1.get('_id'), date: new Date()}]
|
||||
prepaid.save (err) ->
|
||||
expect(err).toBeNull()
|
||||
requestBody = user1.toObject()
|
||||
requestBody.stripe =
|
||||
planID: 'basic'
|
||||
requestBody.stripe.prepaidCode = prepaid.get('code')
|
||||
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'User subscribes, deletes themselves, subscription ends', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
|
@ -596,7 +620,7 @@ describe 'Subscriptions', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
loginNewUser (user2) ->
|
||||
|
@ -607,7 +631,27 @@ describe 'Subscriptions', ->
|
|||
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
||||
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
||||
done()
|
||||
|
||||
it 'User2 subscribes with same active prepaid', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
user1.set('permissions', ['admin'])
|
||||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', 2, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
loginNewUser (user2) ->
|
||||
subscribeUser user2, null, prepaid.code, ->
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('redeemers').length).toEqual(2)
|
||||
done()
|
||||
|
||||
it 'Subscribe normally, subscribe with valid prepaid', (done) ->
|
||||
stripe.tokens.create {
|
||||
|
@ -621,12 +665,14 @@ describe 'Subscriptions', ->
|
|||
subscribeUser user1, token, null, ->
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('status')).toEqual('used')
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
||||
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
||||
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
customerID = user1.get('stripe').customerID
|
||||
|
@ -652,11 +698,13 @@ describe 'Subscriptions', ->
|
|||
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, updatedUser) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('status')).toEqual('used')
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
||||
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
||||
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
customerID = user1.get('stripe').customerID
|
||||
|
@ -673,12 +721,14 @@ describe 'Subscriptions', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('status')).toEqual('used')
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
||||
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
||||
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
unsubscribeUser user1, ->
|
||||
|
@ -693,12 +743,14 @@ describe 'Subscriptions', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
Prepaid.findById prepaid._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('status')).toEqual('used')
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(1)
|
||||
expect(prepaid.get('redeemers')[0].userID).toEqual(user1.get('_id'))
|
||||
expect(prepaid.get('redeemers')[0].date).toBeLessThan(new Date())
|
||||
User.findById user1.id, (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
unsubscribeUser user1, ->
|
||||
|
@ -931,7 +983,7 @@ describe 'Subscriptions', ->
|
|||
user2.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user2.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
requestBody = user2.toObject()
|
||||
requestBody.stripe =
|
||||
|
@ -1103,7 +1155,7 @@ describe 'Subscriptions', ->
|
|||
user1.save (err, user1) ->
|
||||
expect(err).toBeNull()
|
||||
expect(user1.isAdmin()).toEqual(true)
|
||||
createPrepaid 'subscription', (err, res, prepaid) ->
|
||||
createPrepaid 'subscription', 1, (err, res, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
subscribeUser user1, null, prepaid.code, ->
|
||||
stripe.tokens.create {
|
||||
|
|
Loading…
Reference in a new issue