Merge branch 'master' into production

This commit is contained in:
Nick Winter 2014-03-11 19:41:31 -07:00
commit e2e7b876a4
14 changed files with 46 additions and 35 deletions

View file

@ -10,7 +10,7 @@ module.exports = class Simulator
@trigger 'statusUpdate', 'Starting simulation!' @trigger 'statusUpdate', 'Starting simulation!'
@retryDelayInSeconds = 10 @retryDelayInSeconds = 10
@taskURL = '/queue/scoring' @taskURL = '/queue/scoring'
destroy: -> destroy: ->
@off() @off()
@cleanupSimulation() @cleanupSimulation()
@ -25,17 +25,21 @@ module.exports = class Simulator
success: @setupSimulationAndLoadLevel success: @setupSimulationAndLoadLevel
handleFetchTaskError: (errorData) => handleFetchTaskError: (errorData) =>
console.log "There were no games to score. Error: #{JSON.stringify errorData}" console.error "There was a horrible Error: #{JSON.stringify errorData}"
console.log "Retrying in #{@retryDelayInSeconds}" @trigger 'statusUpdate', 'There was an error fetching games to simulate. Retrying in 10 seconds.'
@trigger 'statusUpdate', 'There were no games to simulate! Trying again in 10 seconds.' @simulateAnotherTaskAfterDelay()
handleNoGamesResponse: ->
@trigger 'statusUpdate', 'There were no games to simulate--nice. Retrying in 10 seconds.'
@simulateAnotherTaskAfterDelay() @simulateAnotherTaskAfterDelay()
simulateAnotherTaskAfterDelay: => simulateAnotherTaskAfterDelay: =>
console.log "Retrying in #{@retryDelayInSeconds}"
retryDelayInMilliseconds = @retryDelayInSeconds * 1000 retryDelayInMilliseconds = @retryDelayInSeconds * 1000
_.delay @fetchAndSimulateTask, retryDelayInMilliseconds _.delay @fetchAndSimulateTask, retryDelayInMilliseconds
setupSimulationAndLoadLevel: (taskData) => setupSimulationAndLoadLevel: (taskData, textStatus, jqXHR) =>
return @handleNoGamesResponse() if jqXHR.status is 204
@trigger 'statusUpdate', 'Setting up simulation!' @trigger 'statusUpdate', 'Setting up simulation!'
@task = new SimulationTask(taskData) @task = new SimulationTask(taskData)
@supermodel = new SuperModel() @supermodel = new SuperModel()

View file

@ -151,7 +151,7 @@ class CocoModel extends Backbone.Model
return null unless schema.links? return null unless schema.links?
linkObject = _.find schema.links, rel: "db" linkObject = _.find schema.links, rel: "db"
return null unless linkObject return null unless linkObject
return null if linkObject.href.match("thang_type") and not @isObjectID(data) # Skip loading hardcoded Thang Types for now (TODO) return null if linkObject.href.match("thang.type") and not @isObjectID(data) # Skip loading hardcoded Thang Types for now (TODO)
# not fully extensible, but we can worry about that later # not fully extensible, but we can worry about that later
link = linkObject.href link = linkObject.href

View file

@ -112,7 +112,7 @@ module.exports = class Level extends CocoModel
if path.match(/\/systems\/\d+\/config\//) and data?.indieSprites?.length if path.match(/\/systems\/\d+\/config\//) and data?.indieSprites?.length
# Ugh, we need to make sure we grab the IndieSprite ThangTypes # Ugh, we need to make sure we grab the IndieSprite ThangTypes
for indieSprite in data.indieSprites for indieSprite in data.indieSprites
link = "/db/thang_type/#{indieSprite.thangType}/version" link = "/db/thang.type/#{indieSprite.thangType}/version"
model = CocoModel.getOrMakeModelFromLink link, shouldLoadProjection model = CocoModel.getOrMakeModelFromLink link, shouldLoadProjection
models.push model if model models.push model if model
else if path is '/' else if path is '/'

View file

@ -218,8 +218,8 @@ module.exports = class ThangType extends CocoModel
@loadUniversalWizard: -> @loadUniversalWizard: ->
return @wizardType if @wizardType return @wizardType if @wizardType
wizOriginal = "52a00d55cf1818f2be00000b" wizOriginal = "52a00d55cf1818f2be00000b"
url = "/db/thang_type/#{wizOriginal}/version" url = "/db/thang.type/#{wizOriginal}/version"
@wizardType = new module.exports() @wizardType = new module.exports()
@wizardType.url = -> url @wizardType.url = -> url
@wizardType.fetch() @wizardType.fetch()
@wizardType @wizardType

View file

@ -22,7 +22,7 @@ module.exports = class WizardSettingsView extends CocoView
loadWizard: -> loadWizard: ->
@wizardThangType = new ThangType() @wizardThangType = new ThangType()
@wizardThangType.url = -> '/db/thang_type/wizard' @wizardThangType.url = -> '/db/thang.type/wizard'
@wizardThangType.fetch() @wizardThangType.fetch()
@wizardThangType.once 'sync', @initCanvas, @ @wizardThangType.once 'sync', @initCanvas, @
@ -67,7 +67,7 @@ module.exports = class WizardSettingsView extends CocoView
updateSwatchVisibility: (colorGroup) -> updateSwatchVisibility: (colorGroup) ->
enabled = colorGroup.find('.color-group-checkbox').prop('checked') enabled = colorGroup.find('.color-group-checkbox').prop('checked')
colorGroup.find('.minicolors-swatch').toggle Boolean(enabled) colorGroup.find('.minicolors-swatch').toggle Boolean(enabled)
updateColorSettings: (colorGroup) => updateColorSettings: (colorGroup) =>
wizardSettings = _.cloneDeep(me.get('wizard')) or {} wizardSettings = _.cloneDeep(me.get('wizard')) or {}
wizardSettings.colorConfig ?= {} wizardSettings.colorConfig ?= {}
@ -108,4 +108,4 @@ module.exports = class WizardSettingsView extends CocoView
@movieClip.regX = reg.x @movieClip.regX = reg.x
@movieClip.regY = reg.y @movieClip.regY = reg.y
@stage.addChild @movieClip @stage.addChild @movieClip
@stage.update() @stage.update()

View file

@ -19,7 +19,7 @@ componentOriginals =
"physics.Physical" : "524b75ad7fc0f6d519000001" "physics.Physical" : "524b75ad7fc0f6d519000001"
class ThangTypeSearchCollection extends CocoCollection class ThangTypeSearchCollection extends CocoCollection
url: '/db/thang_type/search?project=true' url: '/db/thang.type/search?project=true'
model: ThangType model: ThangType
module.exports = class ThangsTabView extends View module.exports = class ThangsTabView extends View

View file

@ -122,6 +122,7 @@ module.exports = class MyMatchesTabView extends CocoView
failure = => @setRankingButtonText(button, 'failed') failure = => @setRankingButtonText(button, 'failed')
ajaxData = { session: sessionID, levelID: @level.id, originalLevelID: @level.attributes.original, levelMajorVersion: @level.attributes.version.major } ajaxData = { session: sessionID, levelID: @level.id, originalLevelID: @level.attributes.original, levelMajorVersion: @level.attributes.version.major }
console.log "Posting game for ranking from My Matches view."
$.ajax '/queue/scoring', { $.ajax '/queue/scoring', {
type: 'POST' type: 'POST'
data: ajaxData data: ajaxData

View file

@ -66,6 +66,7 @@ module.exports = class VictoryModal extends View
ajaxData = session: @session.id, levelID: @level.id, originalLevelID: @level.get('original'), levelMajorVersion: @level.get('version').major ajaxData = session: @session.id, levelID: @level.id, originalLevelID: @level.get('original'), levelMajorVersion: @level.get('version').major
ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches" ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
goToLadder = -> Backbone.Mediator.publish 'router:navigate', route: ladderURL goToLadder = -> Backbone.Mediator.publish 'router:navigate', route: ladderURL
console.log "Posting game for ranking from victory modal."
$.ajax '/queue/scoring', $.ajax '/queue/scoring',
type: 'POST' type: 'POST'
data: ajaxData data: ajaxData

View file

@ -174,7 +174,7 @@ LevelThangSchema = c.object {
}, },
id: thang # TODO: figure out if we can make this unique and how to set dynamic defaults id: thang # TODO: figure out if we can make this unique and how to set dynamic defaults
# TODO: split thangType into "original" and "majorVersion" like the rest for consistency # TODO: split thangType into "original" and "majorVersion" like the rest for consistency
thangType: c.objectId(links: [{rel: "db", href: "/db/thang_type/{($)}/version"}], title: "Thang Type", description: "A reference to the original Thang template being configured.", format: 'thang-type') thangType: c.objectId(links: [{rel: "db", href: "/db/thang.type/{($)}/version"}], title: "Thang Type", description: "A reference to the original Thang template being configured.", format: 'thang-type')
components: c.array {title: "Components", description: "Thangs are configured by changing the Components attached to them.", uniqueItems: true, format: 'thang-components-array'}, ThangComponentSchema # TODO: uniqueness should be based on "original", not whole thing components: c.array {title: "Components", description: "Thangs are configured by changing the Components attached to them.", uniqueItems: true, format: 'thang-components-array'}, ThangComponentSchema # TODO: uniqueness should be based on "original", not whole thing
LevelSystemSchema = c.object { LevelSystemSchema = c.object {
@ -252,4 +252,3 @@ module.exports = LevelSchema
# 3. tv4.addSchema(metaschema.id, metaschema) # 3. tv4.addSchema(metaschema.id, metaschema)
# 4. S = <paste big schema here> # 4. S = <paste big schema here>
# 5. tv4.validateMultiple(S, metaschema) and look for errors # 5. tv4.validateMultiple(S, metaschema) and look for errors

View file

@ -61,4 +61,4 @@ LevelThangTypeSchema.plugin(plugins.PermissionsPlugin)
LevelThangTypeSchema.plugin(plugins.NamedPlugin) LevelThangTypeSchema.plugin(plugins.NamedPlugin)
LevelThangTypeSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']}) LevelThangTypeSchema.plugin(plugins.SearchablePlugin, {searchable: ['name', 'description']})
module.exports = LevelThangType = mongoose.model('level.thang_type', LevelThangTypeSchema) module.exports = LevelThangType = mongoose.model('level.thang.type', LevelThangTypeSchema)

View file

@ -84,7 +84,9 @@ module.exports.dispatchTaskToConsumer = (req, res) ->
if isUserAnonymous(req) then return errors.forbidden res, "You need to be logged in to simulate games" if isUserAnonymous(req) then return errors.forbidden res, "You need to be logged in to simulate games"
scoringTaskQueue.receiveMessage (err, message) -> scoringTaskQueue.receiveMessage (err, message) ->
if err? or messageIsInvalid(message) then return errors.gatewayTimeoutError res, "Queue Receive Error:#{err}" if err? or messageIsInvalid(message)
res.send 204, "No games to score. #{message}"
return res.end()
console.log "Received Message" console.log "Received Message"
messageBody = parseTaskQueueMessage req, res, message messageBody = parseTaskQueueMessage req, res, message
return unless messageBody? return unless messageBody?
@ -153,13 +155,16 @@ module.exports.processTaskResult = (req, res) ->
levelOriginalID = levelSession.level.original levelOriginalID = levelSession.level.original
levelOriginalMajorVersion = levelSession.level.majorVersion levelOriginalMajorVersion = levelSession.level.majorVersion
findNearestBetterSessionID levelOriginalID, levelOriginalMajorVersion, originalSessionID, sessionNewScore, opponentNewScore, opponentID ,opposingTeam, (err, opponentSessionID) -> findNearestBetterSessionID levelOriginalID, levelOriginalMajorVersion, originalSessionID, sessionNewScore, opponentNewScore, opponentID, opposingTeam, (err, opponentSessionID) ->
if err? then return errors.serverError res, "There was an error finding the nearest sessionID!" if err? then return errors.serverError res, "There was an error finding the nearest sessionID!"
unless opponentSessionID then return sendResponseObject req, res, {"message":"There were no more games to rank(game is at top!"} if opponentSessionID
addPairwiseTaskToQueue [originalSessionID, opponentSessionID], (err, success) ->
addPairwiseTaskToQueue [originalSessionID, opponentSessionID], (err, success) -> if err? then return errors.serverError res, "There was an error sending the pairwise tasks to the queue!"
if err? then return errors.serverError res, "There was an error sending the pairwise tasks to the queue!" sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"}
sendResponseObject req, res, {"message":"The scores were updated successfully and more games were sent to the queue!"} else
LevelSession.update {_id: originalSessionID}, {isRanking: false}, {multi: false}, (err, affected) ->
if err? then return errors.serverError res, "There was an error marking the victorious session as not being ranked."
return sendResponseObject req, res, {"message":"There were no more games to rank (game is at top)!"}
else else
console.log "Player lost, achieved rank #{originalSessionRank}" console.log "Player lost, achieved rank #{originalSessionRank}"
LevelSession.update {_id: originalSessionID}, {isRanking: false}, {multi: false}, (err, affected) -> LevelSession.update {_id: originalSessionID}, {isRanking: false}, {multi: false}, (err, affected) ->

View file

@ -102,7 +102,7 @@ sendLadderUpdateEmail = (session, daysAgo) ->
score_history_graph_url: getScoreHistoryGraphURL session, daysAgo score_history_graph_url: getScoreHistoryGraphURL session, daysAgo
defeat: defeatContext defeat: defeatContext
victory: victoryContext victory: victoryContext
log.info "Sending ladder update email to #{context.recipient.address} with #{context.email_data.wins} wins and #{context.email_data.losses} since #{daysAgo} day(s) ago." log.info "Sending ladder update email to #{context.recipient.address} with #{context.email_data.wins} wins and #{context.email_data.losses} losses since #{daysAgo} day(s) ago."
sendwithus.api.send context, (err, result) -> sendwithus.api.send context, (err, result) ->
log.error "Error sending ladder update email: #{err} with result #{result}" if err log.error "Error sending ladder update email: #{err} with result #{result}" if err

View file

@ -7,8 +7,8 @@ module.exports.setupRoutes = (app) ->
return return
options = { DEBUG: not config.isProduction } debug = not config.isProduction
module.exports.api = new sendwithusAPI swuAPIKey, options module.exports.api = new sendwithusAPI swuAPIKey, debug
module.exports.templates = module.exports.templates =
welcome_email: 'utnGaBHuSU4Hmsi7qrAypU' welcome_email: 'utnGaBHuSU4Hmsi7qrAypU'
ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4' ladder_update_email: 'JzaZxf39A4cKMxpPZUfWy4'

View file

@ -3,6 +3,7 @@ jsonschema = require('./user_schema')
crypto = require('crypto') crypto = require('crypto')
{salt, isProduction} = require('../../server_config') {salt, isProduction} = require('../../server_config')
mail = require '../commons/mail' mail = require '../commons/mail'
log = require 'winston'
sendwithus = require '../sendwithus' sendwithus = require '../sendwithus'
@ -27,7 +28,7 @@ UserSchema.post('init', ->
UserSchema.methods.isAdmin = -> UserSchema.methods.isAdmin = ->
p = @get('permissions') p = @get('permissions')
return p and 'admin' in p return p and 'admin' in p
UserSchema.statics.updateMailChimp = (doc, callback) -> UserSchema.statics.updateMailChimp = (doc, callback) ->
return callback?() unless isProduction return callback?() unless isProduction
return callback?() if doc.updatedMailChimp return callback?() if doc.updatedMailChimp
@ -41,25 +42,25 @@ UserSchema.statics.updateMailChimp = (doc, callback) ->
return callback?() # don't add totally unsubscribed people to the list return callback?() # don't add totally unsubscribed people to the list
subsChanged = doc.currentSubscriptions isnt JSON.stringify(emailSubs) subsChanged = doc.currentSubscriptions isnt JSON.stringify(emailSubs)
return callback?() unless emailChanged or subsChanged return callback?() unless emailChanged or subsChanged
params = {} params = {}
params.id = mail.MAILCHIMP_LIST_ID params.id = mail.MAILCHIMP_LIST_ID
params.email = if existingProps then {leid:existingProps.leid} else {email:doc.get('email')} params.email = if existingProps then {leid:existingProps.leid} else {email:doc.get('email')}
params.merge_vars = { groupings: [ {id: mail.MAILCHIMP_GROUP_ID, groups: newGroups} ] } params.merge_vars = { groupings: [ {id: mail.MAILCHIMP_GROUP_ID, groups: newGroups} ] }
params.update_existing = true params.update_existing = true
params.double_optin = false params.double_optin = false
onSuccess = (data) -> onSuccess = (data) ->
doc.set('mailChimp', data) doc.set('mailChimp', data)
doc.updatedMailChimp = true doc.updatedMailChimp = true
doc.save() doc.save()
callback?() callback?()
onFailure = (error) -> onFailure = (error) ->
console.error 'failed to subscribe', error, callback? log.error 'failed to subscribe', error, callback?
doc.updatedMailChimp = true doc.updatedMailChimp = true
callback?() callback?()
mc.lists.subscribe params, onSuccess, onFailure mc.lists.subscribe params, onSuccess, onFailure
@ -75,9 +76,9 @@ UserSchema.pre('save', (next) ->
data = data =
email_id: sendwithus.templates.welcome_email email_id: sendwithus.templates.welcome_email
recipient: recipient:
address: @get 'email' address: @get 'email'
sendwithus.api.send data, (err, result) -> sendwithus.api.send data, (err, result) ->
console.log 'error', err, 'result', result log.error 'error', err, 'result', result if err
next() next()
) )
@ -90,4 +91,4 @@ UserSchema.statics.hashPassword = (password) ->
shasum.update(salt + password) shasum.update(salt + password)
shasum.digest('hex') shasum.digest('hex')
module.exports = User = mongoose.model('User', UserSchema) module.exports = User = mongoose.model('User', UserSchema)