Merge branch 'master' into production

This commit is contained in:
Matt Lott 2015-08-13 08:39:02 -07:00
commit 6fb5f270b3
15 changed files with 166 additions and 110 deletions

View file

@ -15,7 +15,8 @@ module.exports = class LevelSetupManager extends CocoClass
super() super()
@supermodel = @options.supermodel ? new SuperModel() @supermodel = @options.supermodel ? new SuperModel()
@session = @options.session @session = @options.session
@loadLevel() unless @level = @options.level
@loadLevel()
if @session if @session
@fillSessionWithDefaults() @fillSessionWithDefaults()
else else

View file

@ -79,8 +79,8 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
adjust_volume: "Ajustar el volumen" adjust_volume: "Ajustar el volumen"
campaign_multiplayer: "Arenas Multijugador" campaign_multiplayer: "Arenas Multijugador"
campaign_multiplayer_description: "... en las que programas cara a cara contra otros jugadores." campaign_multiplayer_description: "... en las que programas cara a cara contra otros jugadores."
# campaign_old_multiplayer: "(Deprecated) Old Multiplayer Arenas" campaign_old_multiplayer: "(Obsoleto) Antiguas Arenas Multijugador"
# campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas." campaign_old_multiplayer_description: "Reliquias de una era más civilizada. Ninguna simulación es ejecutada para estas arenas multijugador antiguas y sin héroes."
share_progress_modal: share_progress_modal:
blurb: "¡Estás haciendo un gran progreso! Cuéntale a alguien cuánto has aprendido con CodeCombat." # {change} blurb: "¡Estás haciendo un gran progreso! Cuéntale a alguien cuánto has aprendido con CodeCombat." # {change}
@ -247,7 +247,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
victory_saving_progress: "Guardando Progreso" victory_saving_progress: "Guardando Progreso"
victory_go_home: "Ir al Inicio" victory_go_home: "Ir al Inicio"
victory_review: "¡Cuéntanos más!" victory_review: "¡Cuéntanos más!"
# victory_review_placeholder: "How was the level?" victory_review_placeholder: "¿Cómo estuvo el nivel?"
victory_hour_of_code_done: "¿Has acabado?" victory_hour_of_code_done: "¿Has acabado?"
victory_hour_of_code_done_yes: "¡Si, he terminado con mi Hora de Código!" victory_hour_of_code_done_yes: "¡Si, he terminado con mi Hora de Código!"
victory_experience_gained: "XP Ganada" victory_experience_gained: "XP Ganada"
@ -284,7 +284,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
time_goto: "Ir a:" time_goto: "Ir a:"
non_user_code_problem_title: "No se puede cargar el nivel" non_user_code_problem_title: "No se puede cargar el nivel"
infinite_loop_title: "Loop infinito detectado" infinite_loop_title: "Loop infinito detectado"
# infinite_loop_description: "The initial code to build the world never finished running. It's probably either really slow or has an infinite loop. Or there might be a bug. You can either try running this code again or reset the code to the default state. If that doesn't fix it, please let us know." infinite_loop_description: "El código inicial para construir el mundo no terminó de ejecutarse. Probablemente es muy lento o tiene un loop infinito. O puede ser un bug. Puedes tratar ejecutando este código nuevamente o reiniciar el código a su estado por defecto. Si eso no lo arregla, haznos saber."
check_dev_console: "Tú puedes también abrir la consola de desarrollo para ver que puede salir mal." check_dev_console: "Tú puedes también abrir la consola de desarrollo para ver que puede salir mal."
check_dev_console_link: "(instrucciones)" check_dev_console_link: "(instrucciones)"
infinite_loop_try_again: "Intentar nuevamente" infinite_loop_try_again: "Intentar nuevamente"
@ -294,7 +294,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
tip_scrub_shortcut: "Ctrl+[ y Ctrl+] rebobina y avance rápido." # {change} tip_scrub_shortcut: "Ctrl+[ y Ctrl+] rebobina y avance rápido." # {change}
tip_guide_exists: "Haga click en la guía en la parte superior de la página para obtener información útil" tip_guide_exists: "Haga click en la guía en la parte superior de la página para obtener información útil"
tip_open_source: "¡CodeCombat es 100% código abierto!" tip_open_source: "¡CodeCombat es 100% código abierto!"
# tip_tell_friends: "Enjoying CodeCombat? Tell your friends about us!" tip_tell_friends: "¿Disfrutando de CodeCombat? ¡Cuéntale a tus amigos acerca de nosotros!"
tip_beta_launch: "CodeCombat lanzó su beta en Octubre del 2013." tip_beta_launch: "CodeCombat lanzó su beta en Octubre del 2013."
tip_think_solution: "Piensa en la solución, no en el problema." tip_think_solution: "Piensa en la solución, no en el problema."
tip_theory_practice: "En teoría, no hay diferencia entre la teoría y la práctica. Pero en la práctica, si la hay. - Yogi Berra" tip_theory_practice: "En teoría, no hay diferencia entre la teoría y la práctica. Pero en la práctica, si la hay. - Yogi Berra"
@ -338,7 +338,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
tip_recurse: "Iterar es humano, recursar es divino. - L. Peter Deutsch" tip_recurse: "Iterar es humano, recursar es divino. - L. Peter Deutsch"
tip_free_your_mind: "Tienes que dejar ir todo, Neo. Miedo, duda, e incredulidad. Libera tu mente. - Morpheus" tip_free_your_mind: "Tienes que dejar ir todo, Neo. Miedo, duda, e incredulidad. Libera tu mente. - Morpheus"
tip_strong_opponents: "Hasta los oponentes mas fuertes siempre tienen una debilidad. - Itachi Uchiha" tip_strong_opponents: "Hasta los oponentes mas fuertes siempre tienen una debilidad. - Itachi Uchiha"
# tip_paper_and_pen: "Before you start coding, you can always plan with a sheet of paper and a pen." tip_paper_and_pen: "Antes de comenzar a codificar, siempre puedes planear con una hoja de papel y un lapicero."
game_menu: game_menu:
inventory_tab: "Inventario" inventory_tab: "Inventario"

View file

@ -1,12 +1,15 @@
c = require './../schemas' 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/{($)}'} ]) 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") code: c.shortString(title: "Unique code to redeem")
type: { type: 'string' } type: { type: 'string' }
status: { enum: ['active', 'used'], default: 'active' }
properties: {type: 'object'} properties: {type: 'object'}
# Deprecated
status: { enum: ['active', 'used'], default: 'active' }
redeemer: c.objectId(links: [ {rel: 'extra', href: '/db/user/{($)}'} ])
}) })
c.extendBasicProperties(PrepaidSchema, 'prepaid') c.extendBasicProperties(PrepaidSchema, 'prepaid')

View file

@ -1,38 +0,0 @@
extends /templates/base
block content
h1(data-i18n="play.choose_your_level") Choose Your Level
p
span(data-i18n="play.adventurer_prefix") You can jump to any level below, or discuss the levels on
a(href="http://discourse.codecombat.com/category/adventurer", data-i18n="play.adventurer_forum") the Adventurer forum
span(data-i18n="play.adventurer_suffix") .
.row
each campaign in campaigns
.campaign-container.col-sm-6
h1
a(href="/play/#{campaign.levels[0].levelPath || 'level'}/#{campaign.levels[0].id}", data-i18n="play.campaign_#{campaign.id}")= campaign.name
p.campaign-description(data-i18n="[html]play.campaign_#{campaign.id}_description")!= campaign.description
each level in campaign.levels
a(href=level.disabled ? "/play" : "/play/#{level.levelPath || 'level'}/#{level.id}", disabled=level.disabled, class=levelStatusMap[level.id] || '')
.level.row
if level.image
img.level-image(src="#{level.image}", alt="#{level.name}")
else
img.level-image(src="/images/generic-icon.png", alt="#{level.name}")
.level-info
h3= level.name + (level.disabled ? " (Coming soon!)" : "")
.level-description= level.description
span(data-i18n="play.level_difficulty") Difficulty:
each i in Array(level.difficulty)
i.icon-star
- var playCount = levelPlayCountMap[level.id]
if playCount
div
span.spr #{playCount.sessions}
span(data-i18n="play.players") players
span.spr , #{Math.round(playCount.playtime / 3600)}
span(data-i18n="play.hours_played") hours played

View file

@ -77,7 +77,7 @@ module.exports = class MainAdminView extends RootView
return unless me.isAdmin() return unless me.isAdmin()
options = options =
url: '/db/prepaid/-/create' url: '/db/prepaid/-/create'
data: {type: 'subscription'} data: {type: 'subscription', maxRedeemers: 1}
method: 'POST' method: 'POST'
options.success = (model, response, options) => options.success = (model, response, options) =>
# TODO: Don't hardcode domain. # TODO: Don't hardcode domain.

View file

@ -97,12 +97,12 @@ module.exports = class ControlBarView extends CocoView
c.homeLink = @homeLink c.homeLink = @homeLink
c c
showGameMenuModal: -> showGameMenuModal: (tab='guide') ->
gameMenuModal = new GameMenuModal level: @level, session: @session, supermodel: @supermodel gameMenuModal = new GameMenuModal level: @level, session: @session, supermodel: @supermodel, showTab: tab
@openModalView gameMenuModal @openModalView gameMenuModal
@listenToOnce gameMenuModal, 'change-hero', -> @listenToOnce gameMenuModal, 'change-hero', ->
@setupManager?.destroy() @setupManager?.destroy()
@setupManager = new LevelSetupManager({supermodel: @supermodel, levelID: @levelID, parent: @, session: @session}) @setupManager = new LevelSetupManager({supermodel: @supermodel, level: @level, levelID: @levelID, parent: @, session: @session})
@setupManager.open() @setupManager.open()
onClickHome: (e) -> onClickHome: (e) ->
@ -111,7 +111,7 @@ module.exports = class ControlBarView extends CocoView
Backbone.Mediator.publish 'router:navigate', route: @homeLink, viewClass: @homeViewClass, viewArgs: @homeViewArgs Backbone.Mediator.publish 'router:navigate', route: @homeLink, viewClass: @homeViewClass, viewArgs: @homeViewArgs
onClickMultiplayer: (e) -> onClickMultiplayer: (e) ->
@openModalView new GameMenuModal showTab: 'multiplayer', level: @level, session: @session, supermodel: @supermodel @showGameMenuModal 'multiplayer'
onClickSignupButton: -> onClickSignupButton: ->
window.tracker?.trackEvent 'Started Signup', category: 'Play Level', label: 'Control Bar', level: @levelID window.tracker?.trackEvent 'Started Signup', category: 'Play Level', label: 'Control Bar', level: @levelID

View file

@ -279,7 +279,7 @@ module.exports = class PlayLevelView extends RootView
e.session.set 'heroConfig', {"thangType":sorcerer,"inventory":{"misc-0":"53e2396a53457600003e3f0f","programming-book":"546e266e9df4a17d0d449be5","minion":"54eb5dbc49fa2d5c905ddf56","feet":"53e214f153457600003e3eab","right-hand":"54eab7f52b7506e891ca7202","left-hand":"5463758f3839c6e02811d30f","wrists":"54693797a2b1f53ce79443e9","gloves":"5469425ca2b1f53ce7944421","torso":"546d4a549df4a17d0d449a97","neck":"54693274a2b1f53ce79443c9","eyes":"546941fda2b1f53ce794441d","head":"546d4ca19df4a17d0d449abf"}} e.session.set 'heroConfig', {"thangType":sorcerer,"inventory":{"misc-0":"53e2396a53457600003e3f0f","programming-book":"546e266e9df4a17d0d449be5","minion":"54eb5dbc49fa2d5c905ddf56","feet":"53e214f153457600003e3eab","right-hand":"54eab7f52b7506e891ca7202","left-hand":"5463758f3839c6e02811d30f","wrists":"54693797a2b1f53ce79443e9","gloves":"5469425ca2b1f53ce7944421","torso":"546d4a549df4a17d0d449a97","neck":"54693274a2b1f53ce79443c9","eyes":"546941fda2b1f53ce794441d","head":"546d4ca19df4a17d0d449abf"}}
else if e.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop'] and not _.size e.session.get('heroConfig')?.inventory ? {} else if e.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop'] and not _.size e.session.get('heroConfig')?.inventory ? {}
@setupManager?.destroy() @setupManager?.destroy()
@setupManager = new LevelSetupManager({supermodel: @supermodel, levelID: @levelID, parent: @, session: @session}) @setupManager = new LevelSetupManager({supermodel: @supermodel, level: @level, levelID: @levelID, parent: @, session: @session})
@setupManager.open() @setupManager.open()
@onRealTimeMultiplayerLevelLoaded e.session if e.level.get('type') in ['hero-ladder', 'course-ladder'] @onRealTimeMultiplayerLevelLoaded e.session if e.level.get('type') in ['hero-ladder', 'course-ladder']
@ -577,7 +577,7 @@ module.exports = class PlayLevelView extends RootView
if slot and not inventory[slot] if slot and not inventory[slot]
# Open up the inventory modal so they can equip the new item # Open up the inventory modal so they can equip the new item
@setupManager?.destroy() @setupManager?.destroy()
@setupManager = new LevelSetupManager({supermodel: @supermodel, levelID: @levelID, parent: @, session: @session, hadEverChosenHero: true}) @setupManager = new LevelSetupManager({supermodel: @supermodel, level: @level, levelID: @levelID, parent: @, session: @session, hadEverChosenHero: true})
@setupManager.open() @setupManager.open()
# Start Real-time Multiplayer ###################################################### # Start Real-time Multiplayer ######################################################

View file

@ -6,6 +6,7 @@ SpellPaletteEntryView = require './SpellPaletteEntryView'
LevelComponent = require 'models/LevelComponent' LevelComponent = require 'models/LevelComponent'
ThangType = require 'models/ThangType' ThangType = require 'models/ThangType'
GameMenuModal = require 'views/play/menu/GameMenuModal' GameMenuModal = require 'views/play/menu/GameMenuModal'
LevelSetupManager = require 'lib/LevelSetupManager'
N_ROWS = 4 N_ROWS = 4
@ -319,10 +320,16 @@ module.exports = class SpellPaletteView extends CocoView
onClickHelp: (e) -> onClickHelp: (e) ->
application.tracker?.trackEvent 'Spell palette help clicked', levelID: @level.get('slug') application.tracker?.trackEvent 'Spell palette help clicked', levelID: @level.get('slug')
@openModalView new GameMenuModal showTab: 'guide', level: @level, session: @session, supermodel: @supermodel gameMenuModal = new GameMenuModal showTab: 'guide', level: @level, session: @session, supermodel: @supermodel
@openModalView gameMenuModal
@listenToOnce gameMenuModal, 'change-hero', ->
@setupManager?.destroy()
@setupManager = new LevelSetupManager({supermodel: @supermodel, level: @level, levelID: @level.get('slug'), parent: @, session: @session})
@setupManager.open()
destroy: -> destroy: ->
entry.destroy() for entry in @entries entry.destroy() for entry in @entries
@toggleBackground = null @toggleBackground = null
$(window).off 'resize', @onResize $(window).off 'resize', @onResize
@setupManager?.destroy()
super() super()

View file

@ -22,7 +22,7 @@ function createPrepaid()
criteria = { criteria = {
creator: creatorID, creator: creatorID,
type: 'subscription', type: 'subscription',
status: 'active', maxRedeemers: 1
code: code, code: code,
properties: { properties: {
couponID: 'free' couponID: 'free'

View file

@ -174,16 +174,51 @@ class SubscriptionHandler extends Handler
return done({res: 'Database error.', code: 500}) return done({res: 'Database error.', code: 500})
return done({res: 'Prepaid not found', code: 404}) unless prepaid? 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 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 # Deprecated: status property
stripeInfo = _.cloneDeep(user.get('stripe') ? {}) if status = prepaid.get('status') and status is 'used'
stripeInfo.couponID = couponID return done({res: 'Prepaid has already been used', code: 403})
stripeInfo.prepaidCode = req.body.stripe.prepaidCode
user.set('stripe', stripeInfo) if prepaid.get('redeemers')?.length >= prepaid.get('maxRedeemers')
@checkForExistingSubscription(req, user, customer, couponID, done) @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 else
couponID = user.get('stripe')?.couponID couponID = user.get('stripe')?.couponID
# SALE LOGIC # SALE LOGIC
@ -257,25 +292,7 @@ class SubscriptionHandler extends Handler
if err if err
@logSubscriptionError(user, 'Stripe user plan saving error. ' + err) @logSubscriptionError(user, 'Stripe user plan saving error. ' + err)
return done({res: 'Database error.', code: 500}) return done({res: 'Database error.', code: 500})
done()
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()
updateStripeRecipientSubscriptions: (req, user, customer, done) -> updateStripeRecipientSubscriptions: (req, user, customer, done) ->
return done({res: 'Database error.', code: 500}) unless req.body.stripe?.subscribeEmails? return done({res: 'Database error.', code: 500}) unless req.body.stripe?.subscribeEmails?

View file

@ -20,13 +20,14 @@ PrepaidHandler = class PrepaidHandler extends Handler
createPrepaid: (req, res) -> createPrepaid: (req, res) ->
return @sendForbiddenError(res) unless @hasAccess(req) return @sendForbiddenError(res) unless @hasAccess(req)
return @sendForbiddenError(res) unless req.body.type is 'subscription' return @sendForbiddenError(res) unless req.body.type is 'subscription'
return @sendForbiddenError(res) unless req.body.maxRedeemers > 0
Prepaid.generateNewCode (code) => Prepaid.generateNewCode (code) =>
return @sendDatabaseError(res, 'Database error.') unless code return @sendDatabaseError(res, 'Database error.') unless code
prepaid = new Prepaid prepaid = new Prepaid
creator: req.user.id creator: req.user.id
type: req.body.type type: req.body.type
status: 'active'
code: code code: code
maxRedeemers: req.body.maxRedeemers
properties: properties:
couponID: 'free' couponID: 'free'
prepaid.save (err) => prepaid.save (err) =>

View file

@ -17,7 +17,7 @@ TrialRequestSchema.pre 'save', (next) ->
prepaid = new Prepaid prepaid = new Prepaid
creator: @get('reviewer') creator: @get('reviewer')
type: 'subscription' type: 'subscription'
status: 'active' maxRedeemers: 1
code: code code: code
properties: properties:
couponID: 'free' couponID: 'free'

View file

@ -118,9 +118,11 @@ wrapUpGetUser = (email, user, done) ->
GLOBAL.getURL = (path) -> GLOBAL.getURL = (path) ->
return 'http://localhost:3001' + path return 'http://localhost:3001' + path
GLOBAL.createPrepaid = (type, done) -> GLOBAL.createPrepaid = (type, maxRedeemers, done) ->
options = uri: GLOBAL.getURL('/db/prepaid/-/create') options = uri: GLOBAL.getURL('/db/prepaid/-/create')
options.json = type: type if type? options.json =
type: type
maxRedeemers: maxRedeemers
request.post options, done request.post options, done
newUserCount = 0 newUserCount = 0

View file

@ -7,7 +7,7 @@ describe '/db/prepaid', ->
verifyPrepaid = (user, prepaid, done) -> verifyPrepaid = (user, prepaid, done) ->
expect(prepaid.creator).toEqual(user.id) expect(prepaid.creator).toEqual(user.id)
expect(prepaid.type).toEqual('subscription') expect(prepaid.type).toEqual('subscription')
expect(prepaid.status).toEqual('active') expect(prepaid.maxRedeemers).toBeGreaterThan(0)
expect(prepaid.code).toMatch(/^\w{8}$/) expect(prepaid.code).toMatch(/^\w{8}$/)
expect(prepaid.properties?.couponID).toEqual('free') expect(prepaid.properties?.couponID).toEqual('free')
done() done()
@ -18,7 +18,7 @@ describe '/db/prepaid', ->
done() done()
it 'Anonymous creates prepaid code', (done) -> it 'Anonymous creates prepaid code', (done) ->
createPrepaid 'subscription', (err, res, body) -> createPrepaid 'subscription', 1, (err, res, body) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(res.statusCode).toBe(401) expect(res.statusCode).toBe(401)
done() done()
@ -26,7 +26,7 @@ describe '/db/prepaid', ->
it 'Non-admin creates prepaid code', (done) -> it 'Non-admin creates prepaid code', (done) ->
loginNewUser (user1) -> loginNewUser (user1) ->
expect(user1.isAdmin()).toEqual(false) expect(user1.isAdmin()).toEqual(false)
createPrepaid 'subscription', (err, res, body) -> createPrepaid 'subscription', 4, (err, res, body) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(res.statusCode).toBe(403) expect(res.statusCode).toBe(403)
done() done()
@ -37,7 +37,7 @@ describe '/db/prepaid', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, body) -> createPrepaid 'subscription', 1, (err, res, body) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(res.statusCode).toBe(200) expect(res.statusCode).toBe(200)
verifyPrepaid user1, body, done verifyPrepaid user1, body, done
@ -48,7 +48,7 @@ describe '/db/prepaid', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'bulldozer', (err, res, body) -> createPrepaid 'bulldozer', 1, (err, res, body) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(res.statusCode).toBe(403) expect(res.statusCode).toBe(403)
done() done()
@ -59,7 +59,18 @@ describe '/db/prepaid', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) 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(err).toBeNull()
expect(res.statusCode).toBe(403) expect(res.statusCode).toBe(403)
done() done()
@ -78,7 +89,7 @@ describe '/db/prepaid', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(res.statusCode).toBe(200) expect(res.statusCode).toBe(200)
request.get {uri: prepaidURL}, (err, res, body) -> request.get {uri: prepaidURL}, (err, res, body) ->

View file

@ -542,14 +542,38 @@ describe 'Subscriptions', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
subscribeUser user1, null, prepaid.code, -> subscribeUser user1, null, prepaid.code, ->
Prepaid.findById prepaid._id, (err, prepaid) -> Prepaid.findById prepaid._id, (err, prepaid) ->
expect(err).toBeNull() 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() 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) -> it 'User subscribes, deletes themselves, subscription ends', (done) ->
stripe.tokens.create { stripe.tokens.create {
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' } card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
@ -596,7 +620,7 @@ describe 'Subscriptions', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
subscribeUser user1, null, prepaid.code, -> subscribeUser user1, null, prepaid.code, ->
loginNewUser (user2) -> loginNewUser (user2) ->
@ -607,7 +631,27 @@ describe 'Subscriptions', ->
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) -> request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, body) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(res.statusCode).toBe(403) 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) -> it 'Subscribe normally, subscribe with valid prepaid', (done) ->
stripe.tokens.create { stripe.tokens.create {
@ -621,12 +665,14 @@ describe 'Subscriptions', ->
subscribeUser user1, token, null, -> subscribeUser user1, token, null, ->
User.findById user1.id, (err, user1) -> User.findById user1.id, (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
subscribeUser user1, null, prepaid.code, -> subscribeUser user1, null, prepaid.code, ->
Prepaid.findById prepaid._id, (err, prepaid) -> Prepaid.findById prepaid._id, (err, prepaid) ->
expect(err).toBeNull() 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) -> User.findById user1.id, (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
customerID = user1.get('stripe').customerID customerID = user1.get('stripe').customerID
@ -652,11 +698,13 @@ describe 'Subscriptions', ->
request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, updatedUser) -> request.put {uri: userURL, json: requestBody, headers: headers }, (err, res, updatedUser) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(res.statusCode).toBe(200) expect(res.statusCode).toBe(200)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
subscribeUser user1, null, prepaid.code, -> subscribeUser user1, null, prepaid.code, ->
Prepaid.findById prepaid._id, (err, prepaid) -> Prepaid.findById prepaid._id, (err, prepaid) ->
expect(err).toBeNull() 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) -> User.findById user1.id, (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
customerID = user1.get('stripe').customerID customerID = user1.get('stripe').customerID
@ -673,12 +721,14 @@ describe 'Subscriptions', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
subscribeUser user1, null, prepaid.code, -> subscribeUser user1, null, prepaid.code, ->
Prepaid.findById prepaid._id, (err, prepaid) -> Prepaid.findById prepaid._id, (err, prepaid) ->
expect(err).toBeNull() 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) -> User.findById user1.id, (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
unsubscribeUser user1, -> unsubscribeUser user1, ->
@ -693,12 +743,14 @@ describe 'Subscriptions', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
subscribeUser user1, null, prepaid.code, -> subscribeUser user1, null, prepaid.code, ->
Prepaid.findById prepaid._id, (err, prepaid) -> Prepaid.findById prepaid._id, (err, prepaid) ->
expect(err).toBeNull() 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) -> User.findById user1.id, (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
unsubscribeUser user1, -> unsubscribeUser user1, ->
@ -931,7 +983,7 @@ describe 'Subscriptions', ->
user2.save (err, user1) -> user2.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user2.isAdmin()).toEqual(true) expect(user2.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
requestBody = user2.toObject() requestBody = user2.toObject()
requestBody.stripe = requestBody.stripe =
@ -1103,7 +1155,7 @@ describe 'Subscriptions', ->
user1.save (err, user1) -> user1.save (err, user1) ->
expect(err).toBeNull() expect(err).toBeNull()
expect(user1.isAdmin()).toEqual(true) expect(user1.isAdmin()).toEqual(true)
createPrepaid 'subscription', (err, res, prepaid) -> createPrepaid 'subscription', 1, (err, res, prepaid) ->
expect(err).toBeNull() expect(err).toBeNull()
subscribeUser user1, null, prepaid.code, -> subscribeUser user1, null, prepaid.code, ->
stripe.tokens.create { stripe.tokens.create {