mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Merge branch 'master' into production
This commit is contained in:
commit
7b88eb772a
24 changed files with 296 additions and 273 deletions
|
@ -1,15 +1,18 @@
|
|||
publishableKey = if application.isProduction() then 'pk_live_27jQZozjDGN1HSUTnSuM578g' else 'pk_test_zG5UwVu6Ww8YhtE9ZYh0JO6a'
|
||||
|
||||
module.exports = handler = StripeCheckout.configure({
|
||||
key: publishableKey
|
||||
name: 'CodeCombat'
|
||||
email: me.get('email')
|
||||
image: "https://codecombat.com/images/pages/base/logo_square_250.png"
|
||||
token: (token) ->
|
||||
console.log 'trigger?', handler.trigger
|
||||
handler.trigger 'received-token', { token: token }
|
||||
Backbone.Mediator.publish 'stripe:received-token', { token: token }
|
||||
locale: 'auto'
|
||||
})
|
||||
|
||||
if StripeCheckout?
|
||||
module.exports = handler = StripeCheckout.configure({
|
||||
key: publishableKey
|
||||
name: 'CodeCombat'
|
||||
email: me.get('email')
|
||||
image: "https://codecombat.com/images/pages/base/logo_square_250.png"
|
||||
token: (token) ->
|
||||
console.log 'trigger?', handler.trigger
|
||||
handler.trigger 'received-token', { token: token }
|
||||
Backbone.Mediator.publish 'stripe:received-token', { token: token }
|
||||
locale: 'auto'
|
||||
})
|
||||
else
|
||||
module.exports = {}
|
||||
console.error "Failure loading StripeCheckout API, returning empty object."
|
||||
_.extend(handler, Backbone.Events)
|
|
@ -123,6 +123,7 @@ module.exports = class LevelBus extends Bus
|
|||
onWinnabilityUpdated: (e) ->
|
||||
return unless @onPoint() and e.winnable
|
||||
return unless e.level.get('slug') in ['ace-of-coders'] # Mirror matches don't otherwise show victory, so we win here.
|
||||
return if @session.get('state')?.complete
|
||||
@onVictory()
|
||||
|
||||
onNewWorldCreated: (e) ->
|
||||
|
|
|
@ -616,11 +616,15 @@
|
|||
cost_premium_server: "CodeCombat is free for the first five levels, after which it costs $9.99 USD per month for access to our other 190+ levels on our exclusive country-specific servers."
|
||||
free_1: "There are 110+ FREE levels which cover every concept."
|
||||
free_2: "A monthly subscription provides access to video tutorials and extra practice levels."
|
||||
teacher_subs_title: "Teachers get free subscriptions!"
|
||||
teacher_subs_0: "We offer free subscriptions to teachers for evaluation purposes."
|
||||
free_3: "The CodeCombat content is divided into"
|
||||
free_4: "courses"
|
||||
free_5: ". The first course is free, and about an hour of material."
|
||||
free_6: "Access to the additional courses can be unlocked with a one-time purchase."
|
||||
teacher_subs_title: "Teachers get a free trial!" # {change}
|
||||
teacher_subs_0: "We offer free trials to teachers." # {change}
|
||||
teacher_subs_1: "Please fill out our"
|
||||
teacher_subs_2: "Teacher Survey"
|
||||
teacher_subs_3: "to set up your subscription."
|
||||
teacher_subs_3: "to try out the paid courses." # {change}
|
||||
sub_includes_title: "What is included in the subscription?"
|
||||
sub_includes_1: "In addition to the 110+ basic levels, students with a monthly subscription get access to these additional features:"
|
||||
sub_includes_2: "80+ practice levels"
|
||||
|
@ -664,16 +668,20 @@
|
|||
title: "Teacher Survey"
|
||||
must_be_logged: "You must be logged in first. Please create an account or log in from the menu above."
|
||||
retrieving: "Retrieving information..."
|
||||
being_reviewed_1: "Your application for a free trial subscription is being"
|
||||
being_reviewed_1: "Your application for a free trial is being" # {change}
|
||||
being_reviewed_2: "reviewed."
|
||||
approved_1: "Your application for a free trial subscription was"
|
||||
approved_1: "Your application for a free trial was" # {change}
|
||||
approved_2: "approved."
|
||||
approved_3: "Further instructions have been sent to"
|
||||
denied_1: "Your application for a free trial subscription has been"
|
||||
approved_4: "Enroll your students on the"
|
||||
approved_5: "courses"
|
||||
approved_6: "page."
|
||||
denied_1: "Your application for a free trial has been" # {change}
|
||||
denied_2: "denied."
|
||||
contact_1: "Please contact"
|
||||
contact_2: "if you have further questions."
|
||||
description_1: "We offer free subscriptions to teachers for evaluation purposes. You can find more information on our"
|
||||
description_1: "We offer free trials to teachers. You will be given 2 free enrollments which can be used to enroll students in paid courses." # {change}
|
||||
description_1b: "You can find more information on our"
|
||||
description_2: "teachers"
|
||||
description_3: "page."
|
||||
description_4: "Please fill out this quick survey and we’ll email you setup instructions."
|
||||
|
|
|
@ -845,19 +845,19 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
|
|||
playtime: "Tempo de Jogo"
|
||||
last_played: "Último Jogo"
|
||||
leagues_explanation: "Jogar em um campeonato contra outros membros do clã nestes casos de arena multiplayer."
|
||||
# track_concepts1: "Track concepts"
|
||||
# track_concepts2a: "learned by each student"
|
||||
# track_concepts2b: "learned by each member"
|
||||
# track_concepts3a: "Track levels completed for each student"
|
||||
# track_concepts3b: "Track levels completed for each member"
|
||||
# track_concepts4a: "See your students'"
|
||||
# track_concepts4b: "See your members'"
|
||||
# track_concepts5: "solutions"
|
||||
# track_concepts6a: "Sort students by name or progress"
|
||||
# track_concepts6b: "Sort members by name or progress"
|
||||
# track_concepts7: "Requires invitation"
|
||||
# track_concepts8: "to join"
|
||||
# private_require_sub: "Private clans require a subscription to create or join."
|
||||
track_concepts1: "Rastrear conceitos"
|
||||
track_concepts2a: "aprendido por cada estudante"
|
||||
track_concepts2b: "aprendido por cada membro"
|
||||
track_concepts3a: "Rastrear níveis completados por cada estudante"
|
||||
track_concepts3b: "Rastrear níveis completados por cada membro"
|
||||
track_concepts4a: "Ver seus alunos'"
|
||||
track_concepts4b: "Ver seus membros'"
|
||||
track_concepts5: "soluções"
|
||||
track_concepts6a: "Classificar alunos por nome ou progresso"
|
||||
track_concepts6b: "Classificar membros por nome ou progresso"
|
||||
track_concepts7: "Requer convite"
|
||||
track_concepts8: "para se juntar"
|
||||
private_require_sub: "Clãs particulares requerem uma assinatura para criar ou juntar-se."
|
||||
|
||||
# courses:
|
||||
# course: "Course"
|
||||
|
|
|
@ -6,13 +6,14 @@ module.exports = class Prepaid extends CocoModel
|
|||
urlRoot: '/db/prepaid'
|
||||
|
||||
openSpots: ->
|
||||
@get('maxRedeemers') - @get('redeemers')?.length
|
||||
return @get('maxRedeemers') - @get('redeemers')?.length if @get('redeemers')?
|
||||
@get('maxRedeemers')
|
||||
|
||||
userHasRedeemed: (userID) ->
|
||||
for redeemer in @get('redeemers')
|
||||
return redeemer.date if redeemer.userID is userID
|
||||
return null
|
||||
|
||||
|
||||
initialize: ->
|
||||
@listenTo @, 'add', ->
|
||||
maxRedeemers = @get('maxRedeemers')
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#teachers-free-trial-view
|
||||
|
||||
.input-email-address
|
||||
width: 40%
|
||||
|
||||
.input-school
|
||||
width: 40%
|
||||
|
||||
|
@ -18,6 +15,9 @@
|
|||
.thanks-submit
|
||||
display: none
|
||||
|
||||
.email-address
|
||||
margin-right: 12px
|
||||
|
||||
.error-message
|
||||
display: none
|
||||
color: red
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
if level.get('type', true) == 'hero-ladder'
|
||||
td.hero-portrait-cell(style="background-image: url(/file/db/thang.type/#{(session.get('heroConfig') || {}).thangType || '529ffbf1cf1818f2be000001'}/portrait.png)")
|
||||
td.rank-cell= rank + 1
|
||||
td.score-cell= Math.round(sessionStats.totalScore * 100)
|
||||
td.score-cell= Math.round((sessionStats.totalScore || session.get('totalScore') / 2) * 100)
|
||||
td(class='name-col-cell' + ((new RegExp('(Simple|Shaman|Brawler|Chieftain|Thoktar) AI')).test(session.get('creatorName')) ? ' ai' : ''))= session.get('creatorName') || "Anonymous"
|
||||
td.age-cell= moment(session.get('submitDate')).fromNow().replace('a few ', '')
|
||||
td.fight-cell
|
||||
|
@ -50,7 +50,7 @@
|
|||
if level.get('type', true) == 'hero-ladder'
|
||||
td.hero-portrait-cell(style="background-image: url(/file/db/thang.type/#{(session.get('heroConfig') || {}).thangType || '529ffbf1cf1818f2be000001'}/portrait.png)")
|
||||
td.rank-cell= session.rank
|
||||
td.score-cell= Math.round(sessionStats.totalScore * 100)
|
||||
td.score-cell= Math.round((sessionStats.totalScore || session.get('totalScore') / 2) * 100)
|
||||
td(class='name-col-cell' + ((new RegExp('(Simple|Shaman|Brawler|Chieftain|Thoktar) AI')).test(session.get('creatorName')) ? ' ai' : ''))= session.get('creatorName') || "Anonymous"
|
||||
td.age-cell= moment(session.get('submitDate')).fromNow().replace('a few ', '')
|
||||
td.fight-cell
|
||||
|
|
|
@ -5,11 +5,12 @@ block modal-header-content
|
|||
|
||||
block modal-body-content
|
||||
|
||||
h4.language-selection(data-i18n="ladder.select_your_language") Select your language!
|
||||
.form-group.select-group
|
||||
select#tome-language(name="language")
|
||||
for option in languages
|
||||
option(value=option.id selected=(language === option.id))= option.name
|
||||
if view.level.get('type') != 'course-ladder'
|
||||
h4.language-selection(data-i18n="ladder.select_your_language") Select your language!
|
||||
.form-group.select-group
|
||||
select#tome-language(name="language")
|
||||
for option in languages
|
||||
option(value=option.id selected=(language === option.id))= option.name
|
||||
|
||||
div#noob-view.secret
|
||||
a(href="/play/level/#{levelID}-tutorial" + (league ? "?league=" + league.id : "")).btn.btn-success.btn-block.btn-lg
|
||||
|
|
|
@ -11,3 +11,7 @@ if !observing
|
|||
|
||||
button.btn.btn-lg.btn-illustrated.btn-success.done-button.secret
|
||||
span(data-i18n="play_level.done") Done
|
||||
|
||||
if view.autoSubmitsToLadder
|
||||
.hidden
|
||||
.ladder-submission-view
|
||||
|
|
|
@ -16,10 +16,14 @@ block content
|
|||
strong(data-i18n="teachers_survey.being_reviewed_2")
|
||||
else if existingRequest.get('status') === 'approved'
|
||||
p
|
||||
span.spr(data-i18n="teachers_survey.approved_1")
|
||||
strong.spr(data-i18n="teachers_survey.approved_2")
|
||||
span.spr(data-i18n="teachers_survey.approved_3")
|
||||
strong= existingRequest.get('properties').email
|
||||
span.spr(data-i18n="teachers_survey.approved_1")
|
||||
strong.spr(data-i18n="teachers_survey.approved_2")
|
||||
span.spr(data-i18n="teachers_survey.approved_3")
|
||||
strong= existingRequest.get('properties').email
|
||||
p
|
||||
span.spr(data-i18n="teachers_survey.approved_4")
|
||||
a(href='/courses', data-i18n="teachers_survey.approved_5")
|
||||
span.spl(data-i18n="teachers_survey.approved_6")
|
||||
else
|
||||
p
|
||||
span.spr(data-i18n="teachers_survey.denied_1")
|
||||
|
@ -29,15 +33,20 @@ block content
|
|||
a(href='mailto:team@codecombat.com') team@codecombat.com
|
||||
span.spl(data-i18n="teachers_survey.contact_2")
|
||||
else
|
||||
p(data-i18n="teachers_survey.description_1")
|
||||
p
|
||||
strong.spr Hour of Code Special!
|
||||
span Complete the survey by December 31st and enroll all your students in the paid courses for 2 months.
|
||||
p
|
||||
span.spr(data-i18n="teachers_survey.description_1")
|
||||
span.spr(data-i18n="teachers_survey.description_1b")
|
||||
a(href='/teachers', data-i18n="teachers_survey.description_2")
|
||||
span.spl(data-i18n="teachers_survey.description_3")
|
||||
p(data-i18n="teachers_survey.description_4")
|
||||
p.container-email-address
|
||||
label.control-label(data-i18n="teachers_survey.email")
|
||||
br
|
||||
input.control-label.input-email-address(type='text', value=view.email)
|
||||
span.email-address= view.email
|
||||
a(href='/account/settings') Change
|
||||
p.container-school
|
||||
label.control-label(data-i18n="teachers_survey.school")
|
||||
br
|
||||
|
|
|
@ -6,17 +6,10 @@ block content
|
|||
p
|
||||
strong Hi Teachers!
|
||||
p We're excited to participate in Hour of Code this year!
|
||||
p We've set up an Introduction to Computer Science course, just for you.
|
||||
p
|
||||
strong How to use CodeCombat with your students:
|
||||
ol
|
||||
li
|
||||
span.spr Navigate to the
|
||||
a(href='/courses/teachers?hoc=true') Courses
|
||||
span.spl page
|
||||
li Click the green 'Get FREE course' button under Introduction to Computer Science
|
||||
li Follow the enrollment instructions
|
||||
li Add students via the 'Add Students' tab
|
||||
span.spr Navigate to the
|
||||
a(href='/courses/teachers?hoc=true') CodeCombat Courses
|
||||
span.spl page to get started.
|
||||
p
|
||||
span.spr If you have any problems, please email
|
||||
a(href='mailto:team@codecombat.com') team@codecombat.com
|
||||
|
@ -25,14 +18,17 @@ block content
|
|||
h2(data-i18n="teachers.more_info")
|
||||
p(data-i18n="teachers.intro_1")
|
||||
p(data-i18n="teachers.intro_2")
|
||||
|
||||
|
||||
h3(data-i18n="teachers.free_title")
|
||||
if me.isOnPremiumServer()
|
||||
p(data-i18n="teachers.cost_premium_server")
|
||||
else
|
||||
p(data-i18n="teachers.free_1")
|
||||
p(data-i18n="teachers.free_2")
|
||||
|
||||
p
|
||||
span.spr(data-i18n="teachers.free_3")
|
||||
a(href='/courses', data-i18n="teachers.free_4")
|
||||
span(data-i18n="teachers.free_5")
|
||||
p(data-i18n="teachers.free_6")
|
||||
p
|
||||
span.spr For more details, please email
|
||||
a(href='mailto:team@codecombat.com') team@codecombat.com
|
||||
|
||||
h3.teachers-title(data-i18n="teachers.teacher_subs_title")
|
||||
p(data-i18n="teachers.teacher_subs_0")
|
||||
p
|
||||
|
@ -40,129 +36,6 @@ block content
|
|||
a(href='/teachers/freetrial', data-i18n="teachers.teacher_subs_2")
|
||||
span.spl(data-i18n="teachers.teacher_subs_3")
|
||||
|
||||
h3(data-i18n="teachers.sub_includes_title")
|
||||
p(data-i18n="teachers.sub_includes_1")
|
||||
ul
|
||||
li(data-i18n="teachers.sub_includes_2")
|
||||
li(data-i18n="teachers.sub_includes_3")
|
||||
li(data-i18n="teachers.sub_includes_4")
|
||||
li(data-i18n="teachers.sub_includes_5")
|
||||
li(data-i18n="teachers.sub_includes_6")
|
||||
li(data-i18n="teachers.sub_includes_7")
|
||||
|
||||
h3(data-i18n="teachers.who_for_title")
|
||||
p(data-i18n="teachers.who_for_1")
|
||||
p(data-i18n="teachers.who_for_2")
|
||||
|
||||
h3(data-i18n="teachers.monitor_progress_title")
|
||||
p
|
||||
span.spr(data-i18n="teachers.monitor_progress_1")
|
||||
a(href='/clans', data-i18n="clans.clan")
|
||||
span.spl(data-i18n="teachers.monitor_progress_2")
|
||||
p
|
||||
span.spr(data-i18n="teachers.monitor_progress_3")
|
||||
a(href='/clans', data-i18n="clans.clans")
|
||||
span.spl(data-i18n="teachers.monitor_progress_4")
|
||||
p(data-i18n="teachers.monitor_progress_5")
|
||||
h4(data-i18n="teachers.sub_includes_7")
|
||||
ul
|
||||
li
|
||||
strong(data-i18n="clans.track_concepts1")
|
||||
span.spl(data-i18n="clans.track_concepts2a")
|
||||
li(data-i18n="clans.track_concepts3a")
|
||||
li
|
||||
span(data-i18n="clans.track_concepts4a")
|
||||
strong.spl(data-i18n="clans.track_concepts5")
|
||||
li(data-i18n="clans.track_concepts6a")
|
||||
li
|
||||
strong(data-i18n="clans.track_concepts7")
|
||||
span.spl(data-i18n="clans.track_concepts8")
|
||||
p
|
||||
img(src='/images/pages/clans/dashboard_preview.png' height='400')
|
||||
p
|
||||
span.spr(data-i18n="teachers.private_clans_2")
|
||||
a(href='/clans', data-i18n="clans.clan")
|
||||
span(data-i18n="teachers.private_clans_3")
|
||||
p(data-i18n="clans.private_require_sub")
|
||||
|
||||
h3(data-i18n="teachers.material_title")
|
||||
if me.isOnPremiumServer()
|
||||
p(data-i18n="teachers.material_premium_server")
|
||||
else
|
||||
p(data-i18n="teachers.material_1")
|
||||
|
||||
h3(data-i18n="teachers.concepts_title")
|
||||
|
||||
//- TODO: i18n for concepts?
|
||||
|
||||
table.table.table-condensed.concepts-table
|
||||
thead
|
||||
tr
|
||||
th
|
||||
a(href='/play/dungeon') Kithgard Dungeon
|
||||
th
|
||||
a(href='/play/forest') Backwoods Forest
|
||||
th
|
||||
a(href='/play/desert') Sarven Desert
|
||||
th
|
||||
a(href='/play/mountain') Cloudrip Mountain
|
||||
tbody
|
||||
tr
|
||||
td Basic Syntax
|
||||
td If Statements
|
||||
td Arithmetic
|
||||
td Object Literals
|
||||
tr
|
||||
td Methods
|
||||
td Relational Operators
|
||||
td While Loops
|
||||
td For Loops
|
||||
tr
|
||||
td Parameters
|
||||
td Object Properties
|
||||
td Break Statements
|
||||
td Functions
|
||||
tr
|
||||
td Strings
|
||||
td Input Handling
|
||||
td Arrays
|
||||
td Drawing
|
||||
tr
|
||||
td Loops
|
||||
td
|
||||
td String Comparison
|
||||
td Modulo
|
||||
tr
|
||||
td Variables
|
||||
td
|
||||
td Finding Min/Max
|
||||
td
|
||||
|
||||
h3(data-i18n="teachers.how_much_title")
|
||||
p
|
||||
span(data-i18n="teachers.how_much_1")
|
||||
span.spr.spl
|
||||
a(href='/account/subscription', data-i18n="teachers.how_much_2")
|
||||
span.spr.spl(data-i18n="teachers.how_much_3")
|
||||
p
|
||||
span.spr(data-i18n="teachers.how_much_5")
|
||||
a(href='mailto:team@codecombat.com') team@codecombat.com
|
||||
span.spl(data-i18n="teachers.how_much_6")
|
||||
p(data-i18n="teachers.how_much_4")
|
||||
h4
|
||||
a(href='/account/subscription', data-i18n="subscribe.group_discounts")
|
||||
p(data-i18n="subscribe.group_discounts_1")
|
||||
table.table.table-condensed.discount-table
|
||||
tr
|
||||
td(data-i18n="subscribe.group_discounts_1st")
|
||||
td(data-i18n="subscribe.group_discounts_full")
|
||||
tr
|
||||
td(data-i18n="subscribe.group_discounts_2nd")
|
||||
td(data-i18n="subscribe.group_discounts_20")
|
||||
tr
|
||||
td(data-i18n="subscribe.group_discounts_12th")
|
||||
td(data-i18n="subscribe.group_discounts_40")
|
||||
|
||||
h3(data-i18n="teachers.more_info_title")
|
||||
p
|
||||
span.spr(data-i18n="teachers.more_info_1")
|
||||
|
|
|
@ -30,7 +30,6 @@ module.exports = class TeachersFreeTrialView extends RootView
|
|||
$('.radio-other').prop("checked", true)
|
||||
|
||||
onClickSubmit: (e) ->
|
||||
email = $('.input-email-address').val()
|
||||
school = $('.input-school').val()
|
||||
location = $('.input-location').val()
|
||||
age = $('input[name=age]:checked').val()
|
||||
|
@ -46,10 +45,6 @@ module.exports = class TeachersFreeTrialView extends RootView
|
|||
$('.container-num-students').removeClass('has-error')
|
||||
$('.container-heard-about').removeClass('has-error')
|
||||
$('.error-message').hide()
|
||||
unless email
|
||||
$('.container-email-address').addClass('has-error')
|
||||
$('.error-message').show()
|
||||
return
|
||||
unless school
|
||||
$('.container-school').addClass('has-error')
|
||||
$('.error-message').show()
|
||||
|
@ -75,7 +70,7 @@ module.exports = class TeachersFreeTrialView extends RootView
|
|||
trialRequest = new TrialRequest
|
||||
type: 'subscription'
|
||||
properties:
|
||||
email: email
|
||||
email: @email
|
||||
school: school
|
||||
location: location
|
||||
age: age
|
||||
|
|
|
@ -4,9 +4,3 @@ template = require 'templates/teachers'
|
|||
module.exports = class TeachersView extends RootView
|
||||
id: 'teachers-view'
|
||||
template: template
|
||||
|
||||
constructor: ->
|
||||
super()
|
||||
_.defer ->
|
||||
# Redirect to HoC version of /courses/teachers until we update the /teachers landing page
|
||||
application.router.navigate "/courses/teachers?hoc=true", trigger: true
|
||||
|
|
|
@ -100,7 +100,7 @@ module.exports = class DiplomatView extends ContributeClassView
|
|||
fr: ['Anon', 'Armaldio', 'ChrisLightman', 'Elfisen', 'Feugy', 'MartinDelille', 'Oaugereau', 'Xeonarno', 'dc55028', 'jaybi', 'pstweb', 'veritable', 'xavismeh'] # français, French
|
||||
ja: ['Coderaulic', 'g1itch', 'kengos', 'treby'] # 日本語, Japanese
|
||||
ar: ['5y', 'ahmed80dz'] # العربية, Arabic
|
||||
'pt-BR': ['Bia41', 'Gutenberg Barros', 'Kieizroe', 'Matthew Burt', 'brunoporto', 'cassiocardoso', 'jklemm'] # português do Brasil, Portuguese (Brazil)
|
||||
'pt-BR': ['Bia41', 'Gutenberg Barros', 'Kieizroe', 'Matthew Burt', 'brunoporto', 'cassiocardoso', 'jklemm', 'Arkhad'] # português do Brasil, Portuguese (Brazil)
|
||||
'pt-PT': ['Imperadeiro98', 'Matthew Burt', 'ProgramadorLucas', 'ReiDuKuduro', 'batista', 'gutierri'] # Português (Portugal), Portuguese (Portugal)
|
||||
pl: ['Anon', 'Kacper Ciepielewski', 'TigroTigro', 'kvasnyk'] # język polski, Polish
|
||||
it: ['AlessioPaternoster', 'flauta', 'Atomk'] # italiano, Italian
|
||||
|
|
|
@ -161,7 +161,9 @@ module.exports = class TeacherCoursesView extends RootView
|
|||
return
|
||||
|
||||
user = @usersToRedeem.first()
|
||||
prepaid = @prepaids.find (prepaid) -> prepaid.openSpots()
|
||||
|
||||
prepaid = @prepaids.find((prepaid) -> prepaid.get('properties').endDate? and prepaid.openSpots())
|
||||
prepaid = @prepaids.find((prepaid) -> prepaid.openSpots()) unless prepaid
|
||||
$.ajax({
|
||||
method: 'POST'
|
||||
url: _.result(prepaid, 'url') + '/redeemers'
|
||||
|
|
|
@ -280,7 +280,10 @@ module.exports = class LadderTabView extends CocoView
|
|||
consolidateFriends: ->
|
||||
allFriendSessions = (@facebookFriendSessions or []).concat(@gplusFriendSessions or [])
|
||||
sessions = _.uniq allFriendSessions, false, (session) -> session._id
|
||||
sessions = _.sortBy sessions, 'totalScore'
|
||||
if @options.league
|
||||
sessions = _.sortBy sessions, (session) -> _.find(session.leagues, leagueID: @options.league.id)?.stats.totalScore ? (session.totalScore / 2)
|
||||
else
|
||||
sessions = _.sortBy sessions, 'totalScore'
|
||||
sessions.reverse()
|
||||
sessions
|
||||
|
||||
|
|
|
@ -120,8 +120,10 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model
|
||||
|
||||
@newEarnedAchievements = []
|
||||
hadOneCompleted = false
|
||||
for achievement in @achievements.models
|
||||
continue unless achievement.completed
|
||||
hadOneCompleted = true
|
||||
ea = new EarnedAchievement({
|
||||
collection: achievement.get('collection')
|
||||
triggeredBy: @session.id
|
||||
|
@ -137,7 +139,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
@updateSavingProgressStatus()
|
||||
me.fetch cache: false unless me.loading
|
||||
|
||||
@readyToContinue = true if not @achievements.models.length
|
||||
@readyToContinue = true unless hadOneCompleted
|
||||
|
||||
# have to use a something resource because addModelResource doesn't handle models being upserted/fetched via POST like we're doing here
|
||||
@newEarnedAchievementsResource = @supermodel.addSomethingResource('earned achievements') if @newEarnedAchievements.length
|
||||
|
|
|
@ -31,6 +31,7 @@ module.exports = class CastButtonView extends CocoView
|
|||
@updateReplayabilityInterval = setInterval @updateReplayability, 1000
|
||||
@observing = options.session.get('creator') isnt me.id
|
||||
@loadMirrorSession() if @options.level.get('slug') in ['ace-of-coders']
|
||||
@autoSubmitsToLadder = @options.level.get('slug') in ['wakka-maul']
|
||||
|
||||
destroy: ->
|
||||
clearInterval @updateReplayabilityInterval
|
||||
|
@ -101,10 +102,10 @@ module.exports = class CastButtonView extends CocoView
|
|||
@casting = false
|
||||
if @hasCastOnce # Don't play this sound the first time
|
||||
@playSound 'cast-end', 0.5
|
||||
# Worked great for live Ace of Coders tournament, but probably annoying for asynchronous tournament mode.
|
||||
#myHeroID = if me.team is 'ogres' then 'Hero Placeholder 1' else 'Hero Placeholder'
|
||||
#if @ladderSubmissionView and not e.world.thangMap[myHeroID]?.errorsOut
|
||||
# _.delay (=> @ladderSubmissionView?.rankSession()), 1000 if @ladderSubmissionView
|
||||
# Worked great for live beginner tournaments, but probably annoying for asynchronous tournament mode.
|
||||
myHeroID = if me.team is 'ogres' then 'Hero Placeholder 1' else 'Hero Placeholder'
|
||||
if @autoSubmitsToLadder and not e.world.thangMap[myHeroID]?.errorsOut
|
||||
_.delay (=> @ladderSubmissionView?.rankSession()), 1000 if @ladderSubmissionView
|
||||
@hasCastOnce = true
|
||||
@updateCastButton()
|
||||
@world = e.world
|
||||
|
|
|
@ -237,11 +237,8 @@ LevelHandler = class LevelHandler extends Handler
|
|||
|
||||
getLeaderboard: (req, res, id) ->
|
||||
sessionsQueryParameters = @makeLeaderboardQueryParameters(req, id)
|
||||
|
||||
sortParameters =
|
||||
'totalScore': req.query.order
|
||||
selectProperties = ['totalScore', 'creatorName', 'creator', 'submittedCodeLanguage', 'heroConfig', 'leagues.leagueID', 'leagues.stats.totalScore', 'submitDate']
|
||||
|
||||
sortParameters = totalScore: req.query.order
|
||||
selectProperties = ['totalScore', 'creatorName', 'creator', 'submittedCodeLanguage', 'heroConfig', 'leagues.leagueID', 'leagues.stats.totalScore', 'submitDate', 'team']
|
||||
query = Session
|
||||
.find(sessionsQueryParameters)
|
||||
.limit(req.query.limit)
|
||||
|
@ -252,7 +249,13 @@ LevelHandler = class LevelHandler extends Handler
|
|||
query.exec (err, resultSessions) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
resultSessions ?= []
|
||||
@sendSuccess res, resultSessions
|
||||
leaderboardOptions = find: sessionsQueryParameters, limit: req.query.limit, sort: sortParameters, select: selectProperties
|
||||
@interleaveAILeaderboardSessions leaderboardOptions, resultSessions, (err, resultSessions) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
if league = req.query['leagues.leagueID']
|
||||
resultSessions = _.sortBy resultSessions, (session) -> _.find(session.get('leagues'), leagueID: league)?.stats.totalScore ? session.get('totalScore') / 2
|
||||
resultSessions.reverse() if sortParameters.totalScore is -1
|
||||
@sendSuccess res, resultSessions
|
||||
|
||||
getMyLeaderboardRank: (req, res, id) ->
|
||||
req.query.order = 1
|
||||
|
@ -283,6 +286,36 @@ LevelHandler = class LevelHandler extends Handler
|
|||
req.query.team ?= 'humans'
|
||||
req.query.limit = parseInt(req.query.limit) ? 20
|
||||
|
||||
ladderBenchmarkAIs: [
|
||||
'564ba6cea33967be1312ae59'
|
||||
'564ba830a33967be1312ae61'
|
||||
'564ba91aa33967be1312ae65'
|
||||
'564ba95ca33967be1312ae69'
|
||||
'564ba9b7a33967be1312ae6d'
|
||||
]
|
||||
|
||||
interleaveAILeaderboardSessions: (leaderboardOptions, sessions, cb) ->
|
||||
return cb null, sessions unless leaderboardOptions.find['leagues.leagueID']
|
||||
return cb null, sessions if leaderboardOptions.limit < 10 # Don't put them in when we're fetching sessions around another session
|
||||
# Get our list of benchmark AI sessions
|
||||
benchmarkSessions = Session
|
||||
.find(level: leaderboardOptions.find.level, creator: {$in: @ladderBenchmarkAIs})
|
||||
.sort(leaderboardOptions.sort)
|
||||
.select(leaderboardOptions.select.join ' ')
|
||||
.cache() # TODO: How long does this cache? We will probably want these to be pretty long.
|
||||
.exec (err, aiSessions) ->
|
||||
return cb err if err
|
||||
matchingAISessions = _.filter aiSessions, (aiSession) ->
|
||||
return false unless aiSession.get('team') is leaderboardOptions.find.team
|
||||
return false if $gt = leaderboardOptions.find.totalScore.$gt and aiSession.get('totalScore') <= $gt
|
||||
return false if $lt = leaderboardOptions.find.totalScore.$lt and aiSession.get('totalScore') >= $lt
|
||||
true
|
||||
# TODO: these aren't real league scores for AIs, but rather the general leaderboard scores, which will make most AI scores artificially high. So we divide by 2 for AI scores not part of the league. Pretty weak, I know. Eventually we'd want them to actually play league matches as if they were in all leagues, but without having infinite space requirements or something? Or change the UI to take them out of the main league table and into their separate area.
|
||||
sessions = _.sortBy sessions.concat(matchingAISessions), (session) -> _.find(session.get('leagues'), leagueID: leaderboardOptions.find['leagues.leagueID'])?.stats.totalScore ? session.get('totalScore') / 2
|
||||
sessions.reverse() if leaderboardOptions.sort.totalScore is -1
|
||||
sessions = sessions.slice 0, leaderboardOptions.limit
|
||||
return cb null, sessions
|
||||
|
||||
getLeaderboardFacebookFriends: (req, res, id) -> @getLeaderboardFriends(req, res, id, 'facebookID')
|
||||
getLeaderboardGPlusFriends: (req, res, id) -> @getLeaderboardFriends(req, res, id, 'gplusID')
|
||||
getLeaderboardFriends: (req, res, id, serviceProperty) ->
|
||||
|
|
|
@ -74,8 +74,9 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) if not prepaid
|
||||
return @sendForbiddenError(res) if prepaid.get('creator').toString() isnt req.user.id
|
||||
return @sendForbiddenError(res) if _.size(prepaid.get('redeemers')) >= prepaid.get('maxRedeemers')
|
||||
return @sendForbiddenError(res) if prepaid.get('redeemers')? and _.size(prepaid.get('redeemers')) >= prepaid.get('maxRedeemers')
|
||||
return @sendForbiddenError(res) unless prepaid.get('type') is 'course'
|
||||
return @sendForbiddenError(res) if prepaid.get('properties')?.endDate < new Date()
|
||||
User.findById(req.body.userID).exec (err, user) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res, 'User for given ID not found') if not user
|
||||
|
@ -85,14 +86,14 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
query =
|
||||
_id: prepaid.get('_id')
|
||||
'redeemers.userID': { $ne: user.get('_id') }
|
||||
$where: "this.redeemers.length < #{prepaid.get('maxRedeemers')}"
|
||||
$where: "this.maxRedeemers > 0 && (!this.redeemers || this.redeemers.length < #{prepaid.get('maxRedeemers')})"
|
||||
update = { $push: { redeemers : { date: new Date(), userID: userID } }}
|
||||
Prepaid.update query, update, (err, nMatched) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
if nMatched is 0
|
||||
@logError(req.user, "POST prepaid redeemer lost race on maxRedeemers")
|
||||
return @sendForbiddenError(res)
|
||||
|
||||
|
||||
user.set('coursePrepaidID', prepaid.get('_id'))
|
||||
user.save (err, user) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
@ -100,7 +101,7 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
redeemers = _.clone(prepaid.get('redeemers') or [])
|
||||
redeemers.push({ date: new Date(), userID: userID })
|
||||
prepaid.set('redeemers', redeemers)
|
||||
@sendSuccess(res, @formatEntity(req, prepaid))
|
||||
@sendSuccess(res, @formatEntity(req, prepaid))
|
||||
|
||||
createPrepaid: (user, type, maxRedeemers, properties, done) ->
|
||||
Prepaid.generateNewCode (code) =>
|
||||
|
@ -241,12 +242,15 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
return @sendBadInputError(res, 'Bad creator') unless utils.isID creator
|
||||
q = {
|
||||
_id: {$gt: cutoffID}
|
||||
creator: mongoose.Types.ObjectId(creator),
|
||||
creator: mongoose.Types.ObjectId(creator)
|
||||
type: 'course'
|
||||
}
|
||||
Prepaid.find q, (err, prepaids) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendSuccess(res, (@formatEntity(req, prepaid) for prepaid in prepaids))
|
||||
documents = []
|
||||
for prepaid in prepaids
|
||||
documents.push(@formatEntity(req, prepaid)) unless prepaid.get('properties')?.endDate < new Date()
|
||||
return @sendSuccess(res, documents)
|
||||
else
|
||||
super(arguments...)
|
||||
|
||||
|
@ -254,5 +258,5 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
prepaid = super(req)
|
||||
prepaid.set('redeemers', [])
|
||||
return prepaid
|
||||
|
||||
|
||||
module.exports = new PrepaidHandler()
|
||||
|
|
|
@ -11,7 +11,6 @@ if config.unittest
|
|||
module.exports.api.send = ->
|
||||
module.exports.templates =
|
||||
parent_subscribe_email: 'tem_2APERafogvwKhmcnouigud'
|
||||
setup_free_sub_email: 'tem_sqdvLCZRwoDQc6jAf5RrQE'
|
||||
share_progress_email: 'tem_VHE3ihhGmVa3727qds9zY8'
|
||||
welcome_email: 'utnGaBHuSU4Hmsi7qrAypU'
|
||||
ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4'
|
||||
|
@ -23,4 +22,5 @@ module.exports.templates =
|
|||
plain_text_email: 'tem_85UvKDCCNPXsFckERTig6Y'
|
||||
next_steps_email: 'tem_RDHhTG5inXQi8pthyqWr5D'
|
||||
course_invite_email: 'tem_u6D2EFWYC5Ptk38bSykjsU'
|
||||
|
||||
teacher_free_trial: 'tem_sqdvLCZRwoDQc6jAf5RrQE'
|
||||
teacher_free_trial_hoc: 'tem_4ZSY9wsA9Qwn4wBFmZgPdc'
|
||||
|
|
|
@ -11,51 +11,41 @@ TrialRequestSchema = new mongoose.Schema {}, {strict: false, minimize: false, re
|
|||
TrialRequestSchema.pre 'save', (next) ->
|
||||
return next() unless @get('status') is 'approved'
|
||||
|
||||
# Add subscription
|
||||
Prepaid.generateNewCode (code) =>
|
||||
unless code
|
||||
log.error "Trial request pre save prepaid gen new code failure"
|
||||
return next()
|
||||
# Add 2 course headcount
|
||||
prepaid = new Prepaid
|
||||
creator: @get('applicant')
|
||||
type: 'course'
|
||||
maxRedeemers: 2
|
||||
properties:
|
||||
trialRequestID: @get('_id')
|
||||
prepaid.save (err) =>
|
||||
if err
|
||||
log.error "Trial request prepaid creation error: #{err}"
|
||||
|
||||
# Special HoC trial: Add 500 course headcount with end date
|
||||
endDate = new Date()
|
||||
endDate.setUTCMonth(endDate.getUTCMonth() + 2)
|
||||
prepaid = new Prepaid
|
||||
creator: @get('reviewer')
|
||||
type: 'subscription'
|
||||
maxRedeemers: 1
|
||||
code: code
|
||||
creator: @get('applicant')
|
||||
type: 'course'
|
||||
maxRedeemers: 500
|
||||
properties:
|
||||
couponID: 'free'
|
||||
endDate: endDate
|
||||
trialRequestID: @get('_id')
|
||||
prepaid.save (err) =>
|
||||
if err
|
||||
log.error "Trial request prepaid creation error: #{err}"
|
||||
return next()
|
||||
@set('prepaidCode', code)
|
||||
|
||||
# Add 2 course headcount
|
||||
prepaid = new Prepaid
|
||||
creator: @get('applicant')
|
||||
type: 'course'
|
||||
maxRedeemers: 2
|
||||
properties:
|
||||
trialRequestID: @get('_id')
|
||||
prepaid.save (err) =>
|
||||
if err
|
||||
log.error "Trial request prepaid creation error: #{err}"
|
||||
next()
|
||||
next()
|
||||
|
||||
TrialRequestSchema.post 'save', (doc) ->
|
||||
if doc.get('status') is 'submitted'
|
||||
msg = "<a href=\"http://codecombat.com/admin/trial-requests\">Trial Request</a> submitted by #{doc.get('properties').email}"
|
||||
msg = "<a href=\"http://codecombat.com/admin/trial-requests\">Trial Request</a> submitted by #{doc.get('properties')?.email}"
|
||||
hipchat.sendHipChatMessage msg, ['tower']
|
||||
else if doc.get('status') is 'approved'
|
||||
ppc = doc.get('prepaidCode')
|
||||
unless ppc
|
||||
log.error 'Trial request post save no ppc'
|
||||
return
|
||||
emailParams =
|
||||
recipient:
|
||||
address: doc.get('properties')?.email
|
||||
email_id: sendwithus.templates.setup_free_sub_email
|
||||
email_data:
|
||||
url: "https://codecombat.com/account/subscription?_ppc=#{ppc}";
|
||||
email_id: sendwithus.templates.teacher_free_trial_hoc
|
||||
sendwithus.api.send emailParams, (err, result) =>
|
||||
log.error "sendwithus trial request approved error: #{err}, result: #{result}" if err
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ describe '/db/prepaid', ->
|
|||
clearModels [Course, CourseInstance, Payment, Prepaid, User], (err) ->
|
||||
throw err if err
|
||||
done()
|
||||
|
||||
|
||||
describe 'POST /db/prepaid/<id>/redeemers', ->
|
||||
|
||||
it 'adds a given user to the redeemers property', (done) ->
|
||||
|
@ -60,7 +60,7 @@ describe '/db/prepaid', ->
|
|||
User.findById otherUser.id, (err, user) ->
|
||||
expect(user.get('coursePrepaidID').equals(prepaid.get('_id'))).toBe(true)
|
||||
done()
|
||||
|
||||
|
||||
it 'does not allow more redeemers than maxRedeemers', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
prepaid = new Prepaid({
|
||||
|
@ -97,7 +97,7 @@ describe '/db/prepaid', ->
|
|||
request.post {uri: url, json: redeemer }, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
|
||||
it 'is idempotent across prepaids collection', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
otherUser = new User({
|
||||
|
@ -125,7 +125,7 @@ describe '/db/prepaid', ->
|
|||
return done() unless res.statusCode is 200
|
||||
expect(body.redeemers.length).toBe(0)
|
||||
done()
|
||||
|
||||
|
||||
it 'is idempotent to itself for a user other than the creator', (done) ->
|
||||
loginNewUser (user1) ->
|
||||
prepaid = new Prepaid({
|
||||
|
@ -184,6 +184,101 @@ describe '/db/prepaid', ->
|
|||
expect(res.statusCode).toBe(200)
|
||||
done()
|
||||
|
||||
it 'return terminal prepaids', (done) ->
|
||||
endDate = new Date()
|
||||
endDate.setUTCMonth(endDate.getUTCMonth() + 2)
|
||||
loginNewUser (user1) ->
|
||||
prepaid = new Prepaid({
|
||||
maxRedeemers: 500,
|
||||
redeemers: [],
|
||||
creator: user1.get('_id')
|
||||
type: 'course'
|
||||
properties:
|
||||
endDate: endDate
|
||||
})
|
||||
prepaid.save (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
url = getURL("/db/prepaid?creator=#{user1.id}")
|
||||
request.get {uri: url}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(200)
|
||||
documents = JSON.parse(body)
|
||||
expect(documents.length).toEqual(1)
|
||||
return done() unless documents.length is 1
|
||||
expect(documents[0]?.properties?.endDate).toEqual(endDate.toISOString())
|
||||
done()
|
||||
|
||||
it 'do not return expired terminal prepaids', (done) ->
|
||||
endDate = new Date()
|
||||
endDate.setUTCMonth(endDate.getUTCMonth() - 1)
|
||||
loginNewUser (user1) ->
|
||||
prepaid = new Prepaid({
|
||||
maxRedeemers: 500,
|
||||
redeemers: [],
|
||||
creator: user1.get('_id')
|
||||
type: 'course'
|
||||
properties:
|
||||
endDate: endDate
|
||||
})
|
||||
prepaid.save (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
url = getURL("/db/prepaid?creator=#{user1.id}")
|
||||
request.get {uri: url}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(200)
|
||||
documents = JSON.parse(body)
|
||||
expect(documents.length).toEqual(0)
|
||||
done()
|
||||
|
||||
it 'redeem terminal prepaids', (done) ->
|
||||
endDate = new Date()
|
||||
endDate.setUTCMonth(endDate.getUTCMonth() + 2)
|
||||
loginNewUser (user1) ->
|
||||
prepaid = new Prepaid({
|
||||
maxRedeemers: 500,
|
||||
redeemers: [],
|
||||
creator: user1.get('_id')
|
||||
type: 'course'
|
||||
properties:
|
||||
endDate: endDate
|
||||
})
|
||||
prepaid.save (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
otherUser = new User()
|
||||
otherUser.save (err, otherUser) ->
|
||||
url = getURL("/db/prepaid/#{prepaid.id}/redeemers")
|
||||
redeemer = { userID: otherUser.id }
|
||||
request.post {uri: url, json: redeemer }, (err, res, body) ->
|
||||
expect(body.redeemers?.length).toBe(1)
|
||||
expect(res.statusCode).toBe(200)
|
||||
return done() unless res.statusCode is 200
|
||||
prepaid = Prepaid.findById body._id, (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
expect(prepaid.get('redeemers').length).toBe(1)
|
||||
User.findById otherUser.id, (err, user) ->
|
||||
expect(user.get('coursePrepaidID').equals(prepaid.get('_id'))).toBe(true)
|
||||
done()
|
||||
|
||||
it 'do not redeem expired terminal prepaids', (done) ->
|
||||
endDate = new Date()
|
||||
endDate.setUTCMonth(endDate.getUTCMonth() - 1)
|
||||
loginNewUser (user1) ->
|
||||
prepaid = new Prepaid({
|
||||
maxRedeemers: 500,
|
||||
redeemers: [],
|
||||
creator: user1.get('_id')
|
||||
type: 'course'
|
||||
properties:
|
||||
endDate: endDate
|
||||
})
|
||||
prepaid.save (err, prepaid) ->
|
||||
expect(err).toBeNull()
|
||||
otherUser = new User()
|
||||
otherUser.save (err, otherUser) ->
|
||||
url = getURL("/db/prepaid/#{prepaid.id}/redeemers")
|
||||
redeemer = { userID: otherUser.id }
|
||||
request.post {uri: url, json: redeemer }, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(403)
|
||||
done()
|
||||
|
||||
it 'Clear database', (done) ->
|
||||
clearModels [Course, CourseInstance, Payment, Prepaid, User], (err) ->
|
||||
throw err if err
|
||||
|
@ -304,7 +399,7 @@ describe '/db/prepaid', ->
|
|||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(422)
|
||||
done()
|
||||
|
||||
|
||||
it 'Standard user purchases a prepaid for 1 seat', (done) ->
|
||||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
|
@ -324,7 +419,7 @@ describe '/db/prepaid', ->
|
|||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toBe(200)
|
||||
verifyCoursePrepaid(user1, prepaid, done)
|
||||
|
||||
|
||||
describe 'Purchase terminal_subscription', ->
|
||||
it 'Anonymous submits a prepaid purchase', (done) ->
|
||||
stripe.tokens.create {
|
||||
|
@ -567,16 +662,16 @@ describe '/db/prepaid', ->
|
|||
stripe.tokens.create {
|
||||
card: { number: '4242424242424242', exp_month: 12, exp_year: 2020, cvc: '123' }
|
||||
}, (err, token) ->
|
||||
loginJoe (joe) ->
|
||||
loginNewUser (user) ->
|
||||
purchasePrepaid 'terminal_subscription', months: 1, 3, token.id, (err, res, prepaid) ->
|
||||
request.get "#{getURL('/db/user')}/#{joe.id}/prepaid_codes", (err, res) ->
|
||||
request.get "#{getURL('/db/user')}/#{user.id}/prepaid_codes", (err, res) ->
|
||||
expect(err).toBeNull()
|
||||
expect(res.statusCode).toEqual(200);
|
||||
codes = JSON.parse res.body
|
||||
expect(codes.length).toEqual(2)
|
||||
expect(codes.length).toEqual(1)
|
||||
expect(codes[0].maxRedeemers).toEqual(3)
|
||||
expect(codes[0].properties).toBeDefined()
|
||||
expect(codes[0].properties.months).toEqual(3)
|
||||
expect(codes[0].properties.months).toEqual(1)
|
||||
done()
|
||||
|
||||
it 'Test for injection', (done) ->
|
||||
|
|
|
@ -120,20 +120,24 @@ describe 'Trial Requests', ->
|
|||
expect(body.reviewDate).toBeDefined()
|
||||
expect(new Date(body.reviewDate)).toBeLessThan(new Date())
|
||||
expect(body.reviewer).toEqual(admin.id)
|
||||
expect(body.prepaidCode).toBeDefined()
|
||||
TrialRequest.findById body._id, (err, doc) ->
|
||||
expect(err).toBeNull()
|
||||
expect(doc.get('status')).toEqual('approved')
|
||||
expect(doc.get('reviewDate')).toBeDefined()
|
||||
expect(new Date(doc.get('reviewDate'))).toBeLessThan(new Date())
|
||||
expect(doc.get('reviewer')).toEqual(admin._id)
|
||||
expect(doc.get('prepaidCode')).toBeDefined()
|
||||
Prepaid.findOne {'properties.trialRequestID': doc.get('_id')}, (err, doc) ->
|
||||
Prepaid.find {'properties.trialRequestID': doc.get('_id')}, (err, prepaids) ->
|
||||
expect(err).toBeNull()
|
||||
return done(err) if err
|
||||
expect(doc.get('type')).toEqual('course')
|
||||
expect(doc.get('creator')).toEqual(user.get('_id'))
|
||||
expect(doc.get('maxRedeemers')).toEqual(2)
|
||||
expect(prepaids.length).toEqual(2)
|
||||
for prepaid in prepaids
|
||||
expect(prepaid.get('type')).toEqual('course')
|
||||
expect(prepaid.get('creator')).toEqual(user.get('_id'))
|
||||
if prepaid.get('properties').endDate
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(500)
|
||||
expect(prepaid.get('properties').endDate).toBeGreaterThan(new Date())
|
||||
else
|
||||
expect(prepaid.get('maxRedeemers')).toEqual(2)
|
||||
done()
|
||||
|
||||
it 'Deny trial request', (done) ->
|
||||
|
|
Loading…
Reference in a new issue