mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-05-04 01:43:40 -04:00
Merge remote-tracking branch 'upstream/master' into i18n-norwegian
This commit is contained in:
commit
fc46075b35
32 changed files with 188 additions and 60 deletions
app
core
lib/simulator
models
views
account
admin
common
core
editor
ladder
LadderPlayModal.coffeeLadderTabView.coffeeLadderView.coffeeMainLadderView.coffeeSimulateTabView.coffee
modal
play
user
scripts/analytics
server/queues
|
@ -23,10 +23,9 @@ definitionSchemas =
|
||||||
init = ->
|
init = ->
|
||||||
return if app
|
return if app
|
||||||
if not window.userObject._id
|
if not window.userObject._id
|
||||||
$.ajax('/auth/whoami', {success: (res) ->
|
$.ajax '/auth/whoami', cache: false, success: (res) ->
|
||||||
window.userObject = res
|
window.userObject = res
|
||||||
init()
|
init()
|
||||||
})
|
|
||||||
return
|
return
|
||||||
|
|
||||||
app = require 'core/application'
|
app = require 'core/application'
|
||||||
|
|
|
@ -136,6 +136,7 @@ module.exports = class Simulator extends CocoClass
|
||||||
parse: true
|
parse: true
|
||||||
error: @handleFetchTaskError
|
error: @handleFetchTaskError
|
||||||
success: @setupSimulationAndLoadLevel
|
success: @setupSimulationAndLoadLevel
|
||||||
|
cache: false
|
||||||
|
|
||||||
handleFetchTaskError: (errorData) =>
|
handleFetchTaskError: (errorData) =>
|
||||||
console.error "There was a horrible Error: #{JSON.stringify errorData}"
|
console.error "There was a horrible Error: #{JSON.stringify errorData}"
|
||||||
|
|
|
@ -367,6 +367,7 @@ class CocoModel extends Backbone.Model
|
||||||
me.fetch (success: -> Backbone.Mediator.publish('achievements:new', earnedAchievements: collection)) unless _.isEmpty(collection.models)
|
me.fetch (success: -> Backbone.Mediator.publish('achievements:new', earnedAchievements: collection)) unless _.isEmpty(collection.models)
|
||||||
error: ->
|
error: ->
|
||||||
console.error 'Miserably failed to fetch unnotified achievements', arguments
|
console.error 'Miserably failed to fetch unnotified achievements', arguments
|
||||||
|
cache: false
|
||||||
|
|
||||||
CocoModel.pollAchievements = _.debounce CocoModel.pollAchievements, 500
|
CocoModel.pollAchievements = _.debounce CocoModel.pollAchievements, 500
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ module.exports = class User extends CocoModel
|
||||||
|
|
||||||
@getUnconflictedName: (name, done) ->
|
@getUnconflictedName: (name, done) ->
|
||||||
$.ajax "/auth/name/#{name}",
|
$.ajax "/auth/name/#{name}",
|
||||||
|
cache: false
|
||||||
success: (data) -> done data.name
|
success: (data) -> done data.name
|
||||||
statusCode: 409: (data) ->
|
statusCode: 409: (data) ->
|
||||||
response = JSON.parse data.responseText
|
response = JSON.parse data.responseText
|
||||||
|
|
|
@ -10,9 +10,9 @@ module.exports = class PaymentsView extends RootView
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super(options)
|
super(options)
|
||||||
@payments = new CocoCollection([], { url: '/db/payment', model: Payment, comparator:'_id' })
|
@payments = new CocoCollection([], { url: '/db/payment', model: Payment, comparator:'_id' })
|
||||||
@supermodel.loadCollection(@payments, 'payments')
|
@supermodel.loadCollection(@payments, 'payments', {cache: false})
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
c.payments = @payments
|
c.payments = @payments
|
||||||
c
|
c
|
||||||
|
|
|
@ -20,11 +20,11 @@ module.exports = class SubscriptionView extends RootView
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super(options)
|
super(options)
|
||||||
if me.get('stripe')
|
if me.get('stripe')
|
||||||
options = { url: "/db/user/#{me.id}/stripe" }
|
options = { cache: false, url: "/db/user/#{me.id}/stripe" }
|
||||||
options.success = (@stripeInfo) =>
|
options.success = (@stripeInfo) =>
|
||||||
@supermodel.addRequestResource('payment_info', options).load()
|
@supermodel.addRequestResource('payment_info', options).load()
|
||||||
@payments = new CocoCollection([], { url: '/db/payment', model: Payment, comparator:'_id' })
|
@payments = new CocoCollection([], { url: '/db/payment', model: Payment, comparator:'_id' })
|
||||||
@supermodel.loadCollection(@payments, 'payments')
|
@supermodel.loadCollection(@payments, 'payments', {cache: false})
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
|
|
|
@ -25,11 +25,11 @@ module.exports = class UnsubscribeView extends RootView
|
||||||
success = =>
|
success = =>
|
||||||
@$el.find('.progress').hide()
|
@$el.find('.progress').hide()
|
||||||
@$el.find('#success-alert').show()
|
@$el.find('#success-alert').show()
|
||||||
me.fetch()
|
me.fetch cache: false
|
||||||
|
|
||||||
error = =>
|
error = =>
|
||||||
@$el.find('.progress').hide()
|
@$el.find('.progress').hide()
|
||||||
@$el.find('#fail-alert').show()
|
@$el.find('#fail-alert').show()
|
||||||
@$el.find('#unsubscribe-button').show()
|
@$el.find('#unsubscribe-button').show()
|
||||||
|
|
||||||
$.ajax { url: url, success: success, error: error }
|
$.ajax { url: url, success: success, error: error, cache: false }
|
||||||
|
|
|
@ -6,18 +6,18 @@ module.exports = class AdministerUserModal extends ModalView
|
||||||
id: "administer-user-modal"
|
id: "administer-user-modal"
|
||||||
template: template
|
template: template
|
||||||
plain: true
|
plain: true
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click #save-changes': 'onSaveChanges'
|
'click #save-changes': 'onSaveChanges'
|
||||||
|
|
||||||
constructor: (options, @userHandle) ->
|
constructor: (options, @userHandle) ->
|
||||||
super(options)
|
super(options)
|
||||||
@user = @supermodel.loadModel(new User({_id:@userHandle}), 'user').model
|
@user = @supermodel.loadModel(new User({_id:@userHandle}), 'user', {cache: false}).model
|
||||||
options = {url: '/stripe/coupons'}
|
options = {cache: false, url: '/stripe/coupons'}
|
||||||
options.success = (@coupons) =>
|
options.success = (@coupons) =>
|
||||||
@couponsResource = @supermodel.addRequestResource('coupon', options)
|
@couponsResource = @supermodel.addRequestResource('coupon', options)
|
||||||
@couponsResource.load()
|
@couponsResource.load()
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
stripe = @user.get('stripe') or {}
|
stripe = @user.get('stripe') or {}
|
||||||
|
@ -40,12 +40,12 @@ module.exports = class AdministerUserModal extends ModalView
|
||||||
c.none = not (c.free or c.freeUntil or c.coupon)
|
c.none = not (c.free or c.freeUntil or c.coupon)
|
||||||
c.user = @user
|
c.user = @user
|
||||||
c
|
c
|
||||||
|
|
||||||
onSaveChanges: ->
|
onSaveChanges: ->
|
||||||
stripe = _.clone(@user.get('stripe') or {})
|
stripe = _.clone(@user.get('stripe') or {})
|
||||||
delete stripe.free
|
delete stripe.free
|
||||||
delete stripe.couponID
|
delete stripe.couponID
|
||||||
|
|
||||||
selection = @$el.find('input[name="stripe-benefit"]:checked').val()
|
selection = @$el.find('input[name="stripe-benefit"]:checked').val()
|
||||||
dateVal = @$el.find('#free-until-date').val()
|
dateVal = @$el.find('#free-until-date').val()
|
||||||
couponVal = @$el.find('#coupon-select').val()
|
couponVal = @$el.find('#coupon-select').val()
|
||||||
|
@ -53,10 +53,8 @@ module.exports = class AdministerUserModal extends ModalView
|
||||||
when 'free' then stripe.free = true
|
when 'free' then stripe.free = true
|
||||||
when 'free-until' then stripe.free = dateVal
|
when 'free-until' then stripe.free = dateVal
|
||||||
when 'coupon' then stripe.couponID = couponVal
|
when 'coupon' then stripe.couponID = couponVal
|
||||||
|
|
||||||
@user.set('stripe', stripe)
|
@user.set('stripe', stripe)
|
||||||
options = {}
|
options = {}
|
||||||
options.success = => @hide()
|
options.success = => @hide()
|
||||||
@user.patch(options)
|
@user.patch(options)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ module.exports = class CLAsView extends RootView
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super options
|
super options
|
||||||
@clas = @supermodel.loadCollection(new CLACollection(), 'clas').model
|
@clas = @supermodel.loadCollection(new CLACollection(), 'clas', {cache: false}).model
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
|
|
|
@ -37,6 +37,7 @@ module.exports = class FilesView extends RootView
|
||||||
$.ajax
|
$.ajax
|
||||||
url: "/file/#{@currentFolder()}/"
|
url: "/file/#{@currentFolder()}/"
|
||||||
success: @onLoadedFiles
|
success: @onLoadedFiles
|
||||||
|
cache: false
|
||||||
|
|
||||||
onLoadedFiles: (res) =>
|
onLoadedFiles: (res) =>
|
||||||
table = tableTemplate({files:res})
|
table = tableTemplate({files:res})
|
||||||
|
|
|
@ -16,7 +16,7 @@ module.exports = class LevelSessionsView extends RootView
|
||||||
@getLevelSessions()
|
@getLevelSessions()
|
||||||
|
|
||||||
getLevelSessions: ->
|
getLevelSessions: ->
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionCollection(), 'sessions').model
|
@sessions = @supermodel.loadCollection(new LevelSessionCollection(), 'sessions', {cache: false}).model
|
||||||
|
|
||||||
getRenderData: =>
|
getRenderData: =>
|
||||||
c = super()
|
c = super()
|
||||||
|
|
|
@ -17,7 +17,7 @@ module.exports = class UserView extends RootView
|
||||||
@user = me
|
@user = me
|
||||||
@onLoaded()
|
@onLoaded()
|
||||||
@user = new User _id: @userID
|
@user = new User _id: @userID
|
||||||
@supermodel.loadModel @user, 'user'
|
@supermodel.loadModel @user, 'user', cache: false
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
context = super()
|
context = super()
|
||||||
|
|
|
@ -39,7 +39,7 @@ module.exports = class RootView extends CocoView
|
||||||
earnedAchievement.set('notified', true)
|
earnedAchievement.set('notified', true)
|
||||||
earnedAchievement.patch()
|
earnedAchievement.patch()
|
||||||
return if achievement.get('collection') is 'level.sessions'
|
return if achievement.get('collection') is 'level.sessions'
|
||||||
return if @isIE() # Some bugs in IE right now, TODO fix soon!
|
#return if @isIE() # Some bugs in IE right now, TODO fix soon! # Maybe working now with not caching achievement fetches in CocoModel?
|
||||||
new AchievementPopup achievement: achievement, earnedAchievement: earnedAchievement
|
new AchievementPopup achievement: achievement, earnedAchievement: earnedAchievement
|
||||||
|
|
||||||
handleNewAchievements: (e) ->
|
handleNewAchievements: (e) ->
|
||||||
|
@ -47,6 +47,7 @@ module.exports = class RootView extends CocoView
|
||||||
achievement = new Achievement(_id: earnedAchievement.get('achievement'))
|
achievement = new Achievement(_id: earnedAchievement.get('achievement'))
|
||||||
achievement.fetch
|
achievement.fetch
|
||||||
success: (achievement) => @showNewAchievement?(achievement, earnedAchievement)
|
success: (achievement) => @showNewAchievement?(achievement, earnedAchievement)
|
||||||
|
cache: false
|
||||||
|
|
||||||
logoutAccount: ->
|
logoutAccount: ->
|
||||||
Backbone.Mediator.publish("auth:logging-out", {})
|
Backbone.Mediator.publish("auth:logging-out", {})
|
||||||
|
|
|
@ -23,7 +23,7 @@ module.exports = class PatchesView extends CocoView
|
||||||
|
|
||||||
load: ->
|
load: ->
|
||||||
@initPatches()
|
@initPatches()
|
||||||
@patches = @supermodel.loadCollection(@patches, 'patches').model
|
@patches = @supermodel.loadCollection(@patches, 'patches', {cache: false}).model
|
||||||
@listenTo @patches, 'sync', @onPatchesLoaded
|
@listenTo @patches, 'sync', @onPatchesLoaded
|
||||||
|
|
||||||
onPatchesLoaded: ->
|
onPatchesLoaded: ->
|
||||||
|
|
|
@ -195,13 +195,13 @@ class ChallengersData
|
||||||
_.extend @, Backbone.Events
|
_.extend @, Backbone.Events
|
||||||
score = @session?.get('totalScore') or 25
|
score = @session?.get('totalScore') or 25
|
||||||
@easyPlayer = new LeaderboardCollection(@level, {order: 1, scoreOffset: score - 5, limit: 1, team: @otherTeam})
|
@easyPlayer = new LeaderboardCollection(@level, {order: 1, scoreOffset: score - 5, limit: 1, team: @otherTeam})
|
||||||
@easyPlayer.fetch()
|
@easyPlayer.fetch cache: false
|
||||||
@listenToOnce(@easyPlayer, 'sync', @challengerLoaded)
|
@listenToOnce(@easyPlayer, 'sync', @challengerLoaded)
|
||||||
@mediumPlayer = new LeaderboardCollection(@level, {order: 1, scoreOffset: score, limit: 1, team: @otherTeam})
|
@mediumPlayer = new LeaderboardCollection(@level, {order: 1, scoreOffset: score, limit: 1, team: @otherTeam})
|
||||||
@mediumPlayer.fetch()
|
@mediumPlayer.fetch cache: false
|
||||||
@listenToOnce(@mediumPlayer, 'sync', @challengerLoaded)
|
@listenToOnce(@mediumPlayer, 'sync', @challengerLoaded)
|
||||||
@hardPlayer = new LeaderboardCollection(@level, {order: -1, scoreOffset: score + 5, limit: 1, team: @otherTeam})
|
@hardPlayer = new LeaderboardCollection(@level, {order: -1, scoreOffset: score + 5, limit: 1, team: @otherTeam})
|
||||||
@hardPlayer.fetch()
|
@hardPlayer.fetch cache: false
|
||||||
@listenToOnce(@hardPlayer, 'sync', @challengerLoaded)
|
@listenToOnce(@hardPlayer, 'sync', @challengerLoaded)
|
||||||
|
|
||||||
challengerLoaded: ->
|
challengerLoaded: ->
|
||||||
|
|
|
@ -154,7 +154,7 @@ module.exports = class LadderTabView extends CocoView
|
||||||
oldLeaderboard.destroy()
|
oldLeaderboard.destroy()
|
||||||
teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
|
teamSession = _.find @sessions.models, (session) -> session.get('team') is team.id
|
||||||
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession, @ladderLimit)
|
@leaderboards[team.id] = new LeaderboardData(@level, team.id, teamSession, @ladderLimit)
|
||||||
@leaderboardRes = @supermodel.addModelResource(@leaderboards[team.id], 'leaderboard', {}, 3)
|
@leaderboardRes = @supermodel.addModelResource(@leaderboards[team.id], 'leaderboard', {cache: false}, 3)
|
||||||
@leaderboardRes.load()
|
@leaderboardRes.load()
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
|
@ -165,7 +165,7 @@ module.exports = class LadderTabView extends CocoView
|
||||||
team = _.find @teams, name: histogramWrapper.data('team-name')
|
team = _.find @teams, name: histogramWrapper.data('team-name')
|
||||||
histogramData = null
|
histogramData = null
|
||||||
$.when(
|
$.when(
|
||||||
$.get("/db/level/#{@level.get('slug')}/histogram_data?team=#{team.name.toLowerCase()}", (data) -> histogramData = data)
|
$.get "/db/level/#{@level.get('slug')}/histogram_data?team=#{team.name.toLowerCase()}", {cache: false}, (data) -> histogramData = data
|
||||||
).then =>
|
).then =>
|
||||||
@generateHistogram(histogramWrapper, histogramData, team.name.toLowerCase()) unless @destroyed
|
@generateHistogram(histogramWrapper, histogramData, team.name.toLowerCase()) unless @destroyed
|
||||||
|
|
||||||
|
@ -294,17 +294,17 @@ module.exports.LeaderboardData = LeaderboardData = class LeaderboardData extends
|
||||||
console.warn 'Already have top players on', @ if @topPlayers
|
console.warn 'Already have top players on', @ if @topPlayers
|
||||||
@topPlayers = new LeaderboardCollection(@level, {order: -1, scoreOffset: HIGHEST_SCORE, team: @team, limit: @limit})
|
@topPlayers = new LeaderboardCollection(@level, {order: -1, scoreOffset: HIGHEST_SCORE, team: @team, limit: @limit})
|
||||||
promises = []
|
promises = []
|
||||||
promises.push @topPlayers.fetch()
|
promises.push @topPlayers.fetch cache: false
|
||||||
|
|
||||||
if @session
|
if @session
|
||||||
score = @session.get('totalScore') or 10
|
score = @session.get('totalScore') or 10
|
||||||
@playersAbove = new LeaderboardCollection(@level, {order: 1, scoreOffset: score, limit: 4, team: @team})
|
@playersAbove = new LeaderboardCollection(@level, {order: 1, scoreOffset: score, limit: 4, team: @team})
|
||||||
promises.push @playersAbove.fetch()
|
promises.push @playersAbove.fetch cache: false
|
||||||
@playersBelow = new LeaderboardCollection(@level, {order: -1, scoreOffset: score, limit: 4, team: @team})
|
@playersBelow = new LeaderboardCollection(@level, {order: -1, scoreOffset: score, limit: 4, team: @team})
|
||||||
promises.push @playersBelow.fetch()
|
promises.push @playersBelow.fetch cache: false
|
||||||
level = "#{@level.get('original')}.#{@level.get('version').major}"
|
level = "#{@level.get('original')}.#{@level.get('version').major}"
|
||||||
success = (@myRank) =>
|
success = (@myRank) =>
|
||||||
promises.push $.ajax "/db/level/#{level}/leaderboard_rank?scoreOffset=#{@session.get('totalScore')}&team=#{@team}", {success}
|
promises.push $.ajax("/db/level/#{level}/leaderboard_rank?scoreOffset=#{@session.get('totalScore')}&team=#{@team}", cache: false, success: success)
|
||||||
@promise = $.when(promises...)
|
@promise = $.when(promises...)
|
||||||
@promise.then @onLoad
|
@promise.then @onLoad
|
||||||
@promise.fail @onFail
|
@promise.fail @onFail
|
||||||
|
|
|
@ -37,7 +37,7 @@ module.exports = class LadderView extends RootView
|
||||||
constructor: (options, @levelID) ->
|
constructor: (options, @levelID) ->
|
||||||
super(options)
|
super(options)
|
||||||
@level = @supermodel.loadModel(new Level(_id: @levelID), 'level').model
|
@level = @supermodel.loadModel(new Level(_id: @levelID), 'level').model
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@levelID), 'your_sessions').model
|
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@levelID), 'your_sessions', {cache: false}).model
|
||||||
|
|
||||||
@teams = []
|
@teams = []
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ module.exports = class LadderView extends RootView
|
||||||
|
|
||||||
fetchSessionsAndRefreshViews: ->
|
fetchSessionsAndRefreshViews: ->
|
||||||
return if @destroyed or application.userIsIdle or (new Date() - 2000 < @lastRefreshTime) or not @supermodel.finished()
|
return if @destroyed or application.userIsIdle or (new Date() - 2000 < @lastRefreshTime) or not @supermodel.finished()
|
||||||
@sessions.fetch({'success': @refreshViews})
|
@sessions.fetch success: @refreshViews, cache: false
|
||||||
|
|
||||||
refreshViews: =>
|
refreshViews: =>
|
||||||
return if @destroyed or application.userIsIdle
|
return if @destroyed or application.userIsIdle
|
||||||
|
|
|
@ -19,7 +19,7 @@ module.exports = class LadderHomeView extends RootView
|
||||||
super options
|
super options
|
||||||
@levelStatusMap = {}
|
@levelStatusMap = {}
|
||||||
@levelPlayCountMap = {}
|
@levelPlayCountMap = {}
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model
|
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
|
||||||
@listenToOnce @sessions, 'sync', @onSessionsLoaded
|
@listenToOnce @sessions, 'sync', @onSessionsLoaded
|
||||||
@getLevelPlayCounts()
|
@getLevelPlayCounts()
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ module.exports = class SimulateTabView extends CocoView
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super(options)
|
super(options)
|
||||||
@simulatorsLeaderboardData = new SimulatorsLeaderboardData(me)
|
@simulatorsLeaderboardData = new SimulatorsLeaderboardData(me)
|
||||||
@simulatorsLeaderboardDataRes = @supermodel.addModelResource(@simulatorsLeaderboardData, 'top_simulators')
|
@simulatorsLeaderboardDataRes = @supermodel.addModelResource(@simulatorsLeaderboardData, 'top_simulators', {cache: false})
|
||||||
@simulatorsLeaderboardDataRes.load()
|
@simulatorsLeaderboardDataRes.load()
|
||||||
require 'vendor/aether-javascript'
|
require 'vendor/aether-javascript'
|
||||||
require 'vendor/aether-python'
|
require 'vendor/aether-python'
|
||||||
|
@ -77,7 +77,7 @@ module.exports = class SimulateTabView extends CocoView
|
||||||
refresh: ->
|
refresh: ->
|
||||||
success = (numberOfGamesInQueue) ->
|
success = (numberOfGamesInQueue) ->
|
||||||
$('#games-in-queue').text numberOfGamesInQueue
|
$('#games-in-queue').text numberOfGamesInQueue
|
||||||
$.ajax '/queue/messagesInQueueCount', {success}
|
$.ajax '/queue/messagesInQueueCount', cache: false, success: success
|
||||||
|
|
||||||
updateSimulationStatus: (simulationStatus, sessions) ->
|
updateSimulationStatus: (simulationStatus, sessions) ->
|
||||||
if simulationStatus is 'Fetching simulation data!'
|
if simulationStatus is 'Fetching simulation data!'
|
||||||
|
@ -131,15 +131,14 @@ class SimulatorsLeaderboardData extends CocoClass
|
||||||
unless @me.get('anonymous')
|
unless @me.get('anonymous')
|
||||||
score = @me.get('simulatedBy') or 0
|
score = @me.get('simulatedBy') or 0
|
||||||
queueSuccess = (@numberOfGamesInQueue) =>
|
queueSuccess = (@numberOfGamesInQueue) =>
|
||||||
promises.push $.ajax '/queue/messagesInQueueCount', {success: queueSuccess}
|
promises.push $.ajax '/queue/messagesInQueueCount', {success: queueSuccess, cache: false}
|
||||||
@playersAbove = new SimulatorsLeaderboardCollection({order: 1, scoreOffset: score, limit: 4})
|
@playersAbove = new SimulatorsLeaderboardCollection({order: 1, scoreOffset: score, limit: 4})
|
||||||
promises.push @playersAbove.fetch()
|
promises.push @playersAbove.fetch()
|
||||||
if score
|
if score
|
||||||
@playersBelow = new SimulatorsLeaderboardCollection({order: -1, scoreOffset: score, limit: 4})
|
@playersBelow = new SimulatorsLeaderboardCollection({order: -1, scoreOffset: score, limit: 4})
|
||||||
promises.push @playersBelow.fetch()
|
promises.push @playersBelow.fetch()
|
||||||
success = (@myRank) =>
|
success = (@myRank) =>
|
||||||
|
promises.push $.ajax("/db/user/me/simulator_leaderboard_rank?scoreOffset=#{score}", cache: false, success: success)
|
||||||
promises.push $.ajax "/db/user/me/simulator_leaderboard_rank?scoreOffset=#{score}", {success}
|
|
||||||
|
|
||||||
@promise = $.when(promises...)
|
@promise = $.when(promises...)
|
||||||
@promise.then @onLoad
|
@promise.then @onLoad
|
||||||
|
|
|
@ -75,7 +75,7 @@ module.exports = class EmployerSignupModal extends ModalView
|
||||||
|
|
||||||
handleAgreementSuccess: (result) ->
|
handleAgreementSuccess: (result) ->
|
||||||
window.tracker?.trackEvent 'Employer Agreed to Contract'
|
window.tracker?.trackEvent 'Employer Agreed to Contract'
|
||||||
me.fetch()
|
me.fetch cache: false
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
|
|
||||||
handleAgreementFailure: (error) ->
|
handleAgreementFailure: (error) ->
|
||||||
|
@ -130,7 +130,7 @@ module.exports = class EmployerSignupModal extends ModalView
|
||||||
@listenTo me, 'sync', =>
|
@listenTo me, 'sync', =>
|
||||||
@render()
|
@render()
|
||||||
IN.parse()
|
IN.parse()
|
||||||
me.fetch()
|
me.fetch cache: false
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
reloadWhenClosed = @reloadWhenClosed
|
reloadWhenClosed = @reloadWhenClosed
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports = class ModelModal extends ModalView
|
||||||
@models = options.models
|
@models = options.models
|
||||||
for model in @models when not model.loaded
|
for model in @models when not model.loaded
|
||||||
@supermodel.loadModel model, 'source_document'
|
@supermodel.loadModel model, 'source_document'
|
||||||
model.fetch()
|
model.fetch cache: false
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
|
|
|
@ -62,7 +62,7 @@ module.exports = class CampaignView extends RootView
|
||||||
@terrain ?= 'dungeon'
|
@terrain ?= 'dungeon'
|
||||||
@levelStatusMap = {}
|
@levelStatusMap = {}
|
||||||
@levelPlayCountMap = {}
|
@levelPlayCountMap = {}
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model
|
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
|
||||||
@listenToOnce @sessions, 'sync', @onSessionsLoaded
|
@listenToOnce @sessions, 'sync', @onSessionsLoaded
|
||||||
unless @terrain
|
unless @terrain
|
||||||
@campaigns = @supermodel.loadCollection(new CampaignsCollection(), 'campaigns', null, 0).model
|
@campaigns = @supermodel.loadCollection(new CampaignsCollection(), 'campaigns', null, 0).model
|
||||||
|
@ -85,7 +85,7 @@ module.exports = class CampaignView extends RootView
|
||||||
console.warn 'Filling in a gap for reward', group, reward
|
console.warn 'Filling in a gap for reward', group, reward
|
||||||
earned[group].push(reward)
|
earned[group].push(reward)
|
||||||
|
|
||||||
@supermodel.loadCollection(@earnedAchievements, 'achievements')
|
@supermodel.loadCollection(@earnedAchievements, 'achievements', {cache: false})
|
||||||
|
|
||||||
@listenToOnce @campaign, 'sync', @getLevelPlayCounts
|
@listenToOnce @campaign, 'sync', @getLevelPlayCounts
|
||||||
$(window).on 'resize', @onWindowResize
|
$(window).on 'resize', @onWindowResize
|
||||||
|
@ -375,7 +375,7 @@ module.exports = class CampaignView extends RootView
|
||||||
sessionURL = "/db/level/#{levelSlug}/session"
|
sessionURL = "/db/level/#{levelSlug}/session"
|
||||||
@preloadedSession = new LevelSession().setURL sessionURL
|
@preloadedSession = new LevelSession().setURL sessionURL
|
||||||
@listenToOnce @preloadedSession, 'sync', @onSessionPreloaded
|
@listenToOnce @preloadedSession, 'sync', @onSessionPreloaded
|
||||||
@preloadedSession = @supermodel.loadModel(@preloadedSession, 'level_session').model
|
@preloadedSession = @supermodel.loadModel(@preloadedSession, 'level_session', {cache: false}).model
|
||||||
@preloadedSession.levelSlug = levelSlug
|
@preloadedSession.levelSlug = levelSlug
|
||||||
|
|
||||||
onSessionPreloaded: (session) ->
|
onSessionPreloaded: (session) ->
|
||||||
|
|
|
@ -19,7 +19,7 @@ module.exports = class MainPlayView extends RootView
|
||||||
super options
|
super options
|
||||||
@levelStatusMap = {}
|
@levelStatusMap = {}
|
||||||
@levelPlayCountMap = {}
|
@levelPlayCountMap = {}
|
||||||
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', null, 0).model
|
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
|
||||||
@listenToOnce @sessions, 'sync', @onSessionsLoaded
|
@listenToOnce @sessions, 'sync', @onSessionsLoaded
|
||||||
@getLevelPlayCounts()
|
@getLevelPlayCounts()
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,7 @@ module.exports = class SpectateLevelView extends RootView
|
||||||
$.ajax
|
$.ajax
|
||||||
url: randomSessionPairURL
|
url: randomSessionPairURL
|
||||||
type: 'GET'
|
type: 'GET'
|
||||||
|
cache: false
|
||||||
complete: (jqxhr, textStatus) ->
|
complete: (jqxhr, textStatus) ->
|
||||||
if textStatus isnt 'success'
|
if textStatus isnt 'success'
|
||||||
cb('error', jqxhr.statusText)
|
cb('error', jqxhr.statusText)
|
||||||
|
|
|
@ -39,7 +39,7 @@ module.exports = class VictoryModal extends ModalView
|
||||||
url = "/db/level/#{@level.id}/feedback"
|
url = "/db/level/#{@level.id}/feedback"
|
||||||
@feedback = new LevelFeedback()
|
@feedback = new LevelFeedback()
|
||||||
@feedback.setURL url
|
@feedback.setURL url
|
||||||
@feedback.fetch()
|
@feedback.fetch cache: false
|
||||||
@listenToOnce(@feedback, 'sync', -> @onFeedbackLoaded())
|
@listenToOnce(@feedback, 'sync', -> @onFeedbackLoaded())
|
||||||
@listenToOnce(@feedback, 'error', -> @onFeedbackNotFound())
|
@listenToOnce(@feedback, 'error', -> @onFeedbackNotFound())
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ module.exports = class LeaderboardTabView extends CocoView
|
||||||
return if @hasShown
|
return if @hasShown
|
||||||
@hasShown = true
|
@hasShown = true
|
||||||
topScores = new TopScoresCollection @level, @scoreType, @timespan
|
topScores = new TopScoresCollection @level, @scoreType, @timespan
|
||||||
@sessions = @supermodel.loadCollection(topScores, 'sessions', null, 0).model
|
@sessions = @supermodel.loadCollection(topScores, 'sessions', {cache: false}, 0).model
|
||||||
|
|
||||||
onClickRow: (e) ->
|
onClickRow: (e) ->
|
||||||
sessionID = $(e.target).closest('tr').data 'session-id'
|
sessionID = $(e.target).closest('tr').data 'session-id'
|
||||||
|
|
|
@ -36,9 +36,9 @@ module.exports = class PlayAchievementsModal extends ModalView
|
||||||
earnedAchievementsFetcher.setProjection([ 'achievement' ])
|
earnedAchievementsFetcher.setProjection([ 'achievement' ])
|
||||||
|
|
||||||
achievementsFetcher.skip = 0
|
achievementsFetcher.skip = 0
|
||||||
achievementsFetcher.fetch({data: {skip: 0, limit: PAGE_SIZE}})
|
achievementsFetcher.fetch cache: false, data: {skip: 0, limit: PAGE_SIZE}
|
||||||
earnedAchievementsFetcher.skip = 0
|
earnedAchievementsFetcher.skip = 0
|
||||||
earnedAchievementsFetcher.fetch({data: {skip: 0, limit: PAGE_SIZE}})
|
earnedAchievementsFetcher.fetch cache: false, data: {skip: 0, limit: PAGE_SIZE}
|
||||||
|
|
||||||
@listenTo achievementsFetcher, 'sync', @onAchievementsLoaded
|
@listenTo achievementsFetcher, 'sync', @onAchievementsLoaded
|
||||||
@listenTo earnedAchievementsFetcher, 'sync', @onEarnedAchievementsLoaded
|
@listenTo earnedAchievementsFetcher, 'sync', @onEarnedAchievementsLoaded
|
||||||
|
@ -53,7 +53,7 @@ module.exports = class PlayAchievementsModal extends ModalView
|
||||||
@achievements.add(fetcher.models)
|
@achievements.add(fetcher.models)
|
||||||
if needMore
|
if needMore
|
||||||
fetcher.skip += PAGE_SIZE
|
fetcher.skip += PAGE_SIZE
|
||||||
fetcher.fetch({data: {skip: fetcher.skip, limit: PAGE_SIZE}})
|
fetcher.fetch cache: false, data: {skip: fetcher.skip, limit: PAGE_SIZE}
|
||||||
else
|
else
|
||||||
@stopListening(fetcher)
|
@stopListening(fetcher)
|
||||||
@onEverythingLoaded()
|
@onEverythingLoaded()
|
||||||
|
@ -64,7 +64,7 @@ module.exports = class PlayAchievementsModal extends ModalView
|
||||||
@earnedMap[earned.get('achievement')] = earned
|
@earnedMap[earned.get('achievement')] = earned
|
||||||
if needMore
|
if needMore
|
||||||
fetcher.skip += PAGE_SIZE
|
fetcher.skip += PAGE_SIZE
|
||||||
fetcher.fetch({data: {skip: fetcher.skip, limit: PAGE_SIZE}})
|
fetcher.fetch cache: false, data: {skip: fetcher.skip, limit: PAGE_SIZE}
|
||||||
else
|
else
|
||||||
@stopListening(fetcher)
|
@stopListening(fetcher)
|
||||||
@onEverythingLoaded()
|
@onEverythingLoaded()
|
||||||
|
|
|
@ -85,7 +85,7 @@ module.exports = class JobProfileView extends UserView
|
||||||
# Mimicking how the VictoryModal fetches LevelFeedback
|
# Mimicking how the VictoryModal fetches LevelFeedback
|
||||||
@remark = new UserRemark()
|
@remark = new UserRemark()
|
||||||
@remark.setURL "/db/user/#{@userID}/remark"
|
@remark.setURL "/db/user/#{@userID}/remark"
|
||||||
@remark.fetch()
|
@remark.fetch cache: false
|
||||||
@listenToOnce @remark, 'sync', @onRemarkLoaded
|
@listenToOnce @remark, 'sync', @onRemarkLoaded
|
||||||
@listenToOnce @remark, 'error', @onRemarkNotFound
|
@listenToOnce @remark, 'error', @onRemarkNotFound
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class LevelSessionsCollection extends CocoCollection
|
||||||
module.exports = class MainUserView extends UserView
|
module.exports = class MainUserView extends UserView
|
||||||
id: 'user-home'
|
id: 'user-home'
|
||||||
template: template
|
template: template
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'click .more-button': 'onClickMoreButton'
|
'click .more-button': 'onClickMoreButton'
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ module.exports = class MainUserView extends UserView
|
||||||
@supermodel.resetProgress()
|
@supermodel.resetProgress()
|
||||||
@levelSessions = new LevelSessionsCollection @user.getSlugOrID()
|
@levelSessions = new LevelSessionsCollection @user.getSlugOrID()
|
||||||
@earnedAchievements = new EarnedAchievementCollection @user.getSlugOrID()
|
@earnedAchievements = new EarnedAchievementCollection @user.getSlugOrID()
|
||||||
@supermodel.loadCollection @levelSessions, 'levelSessions'
|
@supermodel.loadCollection @levelSessions, 'levelSessions', {cache: false}
|
||||||
@supermodel.loadCollection @earnedAchievements, 'earnedAchievements'
|
@supermodel.loadCollection @earnedAchievements, 'earnedAchievements', {cache: false}
|
||||||
super()
|
super()
|
||||||
|
|
||||||
onClickMoreButton: (e) ->
|
onClickMoreButton: (e) ->
|
||||||
panel = $(e.target).closest('.panel')
|
panel = $(e.target).closest('.panel')
|
||||||
panel.find('tr.hide').removeClass('hide')
|
panel.find('tr.hide').removeClass('hide')
|
||||||
panel.find('.panel-footer').remove()
|
panel.find('.panel-footer').remove()
|
||||||
|
|
122
scripts/analytics/mixpanelABGemPrompt.py
Normal file
122
scripts/analytics/mixpanelABGemPrompt.py
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
# Calculate gem prompt A/B test results
|
||||||
|
|
||||||
|
# TODO: Why is no-prompt group 50% larger?
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from mixpanel import Mixpanel
|
||||||
|
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
except ImportError:
|
||||||
|
import simplejson as json
|
||||||
|
|
||||||
|
# NOTE: mixpanel dates are by day and inclusive
|
||||||
|
# E.g. '2014-12-08' is any date that day, up to 2014-12-09 12am
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if not len(sys.argv) is 3:
|
||||||
|
print "Script format: <script> <api_key> <api_secret>"
|
||||||
|
else:
|
||||||
|
api_key = sys.argv[1]
|
||||||
|
api_secret = sys.argv[2]
|
||||||
|
api = Mixpanel(
|
||||||
|
api_key = api_key,
|
||||||
|
api_secret = api_secret
|
||||||
|
)
|
||||||
|
|
||||||
|
startDate = '2015-01-15'
|
||||||
|
startDate = '2014-11-25'
|
||||||
|
endDate = '2015-02-11'
|
||||||
|
|
||||||
|
print("Requesting data for {0} to {1}".format(startDate, endDate))
|
||||||
|
data = api.request(['export'], {
|
||||||
|
'event' : ['Started purchase', 'Finished gem purchase'],
|
||||||
|
'from_date' : startDate,
|
||||||
|
'to_date' : endDate
|
||||||
|
})
|
||||||
|
|
||||||
|
userProgressionGroupA = {}
|
||||||
|
userProgressionGroupB = {}
|
||||||
|
|
||||||
|
lines = data.split('\n')
|
||||||
|
print "Received %d entries" % len(lines)
|
||||||
|
for line in lines:
|
||||||
|
try:
|
||||||
|
if len(line) is 0: continue
|
||||||
|
eventData = json.loads(line)
|
||||||
|
eventName = eventData['event']
|
||||||
|
properties = eventData['properties']
|
||||||
|
if not eventName in ['Started purchase', 'Finished gem purchase']:
|
||||||
|
print 'Unexpected event ' + eventName
|
||||||
|
break
|
||||||
|
if 'distinct_id' in properties and 'gemPromptGroup' in properties:
|
||||||
|
userID = properties['distinct_id']
|
||||||
|
if properties['gemPromptGroup'] == 'prompt':
|
||||||
|
if not userID in userProgressionGroupA:
|
||||||
|
userProgressionGroupA[userID] = {
|
||||||
|
'Started purchase': 0,
|
||||||
|
'Finished gem purchase': 0
|
||||||
|
}
|
||||||
|
userProgressionGroupA[userID][eventName] += 1
|
||||||
|
elif properties['gemPromptGroup'] == 'no-prompt':
|
||||||
|
if not userID in userProgressionGroupB:
|
||||||
|
userProgressionGroupB[userID] = {
|
||||||
|
'Started purchase': 0,
|
||||||
|
'Finished gem purchase': 0
|
||||||
|
}
|
||||||
|
userProgressionGroupB[userID][eventName] += 1
|
||||||
|
else:
|
||||||
|
print "Unexpected group:", properties['gemPromptGroup']
|
||||||
|
print properties
|
||||||
|
print line
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
print "Unexpected error:", sys.exc_info()[0]
|
||||||
|
print line
|
||||||
|
break
|
||||||
|
|
||||||
|
try:
|
||||||
|
started = converted = 0
|
||||||
|
startedGroupA = convertedGroupA = 0
|
||||||
|
startedGroupB = convertedGroupB = 0
|
||||||
|
|
||||||
|
# Group A
|
||||||
|
print("Processing Group A")
|
||||||
|
for key, item in userProgressionGroupA.iteritems():
|
||||||
|
if item['Finished gem purchase'] > 0:
|
||||||
|
converted += 1
|
||||||
|
convertedGroupA += 1
|
||||||
|
# TODO: is our distinct_id correct? We hit this at least once.
|
||||||
|
# if item['Finished gem purchase'] > 1:
|
||||||
|
# print "User multiple subcription purchases?"
|
||||||
|
# print item
|
||||||
|
elif item['Started purchase'] > 0:
|
||||||
|
started += 1
|
||||||
|
startedGroupA += 1
|
||||||
|
else:
|
||||||
|
print "User without any hits?"
|
||||||
|
print item
|
||||||
|
break
|
||||||
|
|
||||||
|
# Group B
|
||||||
|
print("Processing Group B")
|
||||||
|
for key, item in userProgressionGroupB.iteritems():
|
||||||
|
if item['Finished gem purchase'] > 0:
|
||||||
|
converted += 1
|
||||||
|
convertedGroupB += 1
|
||||||
|
elif item['Started purchase'] > 0:
|
||||||
|
started += 1
|
||||||
|
startedGroupB += 1
|
||||||
|
else:
|
||||||
|
print "User without any hits?"
|
||||||
|
print item
|
||||||
|
break
|
||||||
|
|
||||||
|
print("Overall")
|
||||||
|
print("started {0} converted {1} rate {2}%".format(started, converted, float(converted) / started * 100))
|
||||||
|
print("Group prompt")
|
||||||
|
print("startedGroupA {0} convertedGroupA {1} rate {2}%".format(startedGroupA, convertedGroupA, float(convertedGroupA) / startedGroupA * 100))
|
||||||
|
print("Group no-prompt")
|
||||||
|
print("startedGroupB {0} convertedGroupB {1} rate {2}%".format(startedGroupB, convertedGroupB, float(convertedGroupB) / startedGroupB * 100))
|
||||||
|
except:
|
||||||
|
print "Unexpected error:", sys.exc_info()[0]
|
|
@ -4,11 +4,14 @@
|
||||||
// Usage:
|
// Usage:
|
||||||
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
||||||
|
|
||||||
|
// TODO: Why is no-prompt group 50% larger?
|
||||||
|
|
||||||
load('abTestHelpers.js');
|
load('abTestHelpers.js');
|
||||||
|
|
||||||
var scriptStartTime = new Date();
|
var scriptStartTime = new Date();
|
||||||
try {
|
try {
|
||||||
var startDay = '2014-11-24'
|
var startDay = '2014-11-24'
|
||||||
|
// startDay = '2015-01-15'
|
||||||
log("Today is " + new Date().toISOString().substr(0, 10));
|
log("Today is " + new Date().toISOString().substr(0, 10));
|
||||||
log("Start day is " + startDay);
|
log("Start day is " + startDay);
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,8 @@ module.exports.getTwoGames = (req, res) ->
|
||||||
#if userIsAnonymous req then return errors.unauthorized(res, 'You need to be logged in to get games.')
|
#if userIsAnonymous req then return errors.unauthorized(res, 'You need to be logged in to get games.')
|
||||||
humansGameID = req.body.humansGameID
|
humansGameID = req.body.humansGameID
|
||||||
ogresGameID = req.body.ogresGameID
|
ogresGameID = req.body.ogresGameID
|
||||||
ladderGameIDs = ['greed', 'criss-cross', 'brawlwood', 'dungeon-arena', 'gold-rush', 'sky-span', 'dueling-grounds', 'cavern-survival', 'multiplayer-treasure-grove']
|
#ladderGameIDs = ['greed', 'criss-cross', 'brawlwood', 'dungeon-arena', 'gold-rush', 'sky-span'] # Let's not give any extra simulations to old ladders.
|
||||||
|
ladderGameIDs = ['dueling-grounds', 'cavern-survival', 'multiplayer-treasure-grove']
|
||||||
levelID = _.sample ladderGameIDs
|
levelID = _.sample ladderGameIDs
|
||||||
sortLimit = 200
|
sortLimit = 200
|
||||||
unless ogresGameID and humansGameID
|
unless ogresGameID and humansGameID
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue