2015-08-13 14:17:38 -04:00
|
|
|
log = require 'winston'
|
|
|
|
async = require 'async'
|
|
|
|
errors = require '../../commons/errors'
|
|
|
|
scoringUtils = require './scoringUtils'
|
2016-04-06 13:56:06 -04:00
|
|
|
LevelSession = require '../../models/LevelSession'
|
|
|
|
Level = require '../../models/Level'
|
2015-08-13 14:17:38 -04:00
|
|
|
|
|
|
|
module.exports = createNewTask = (req, res) ->
|
|
|
|
requestSessionID = req.body.session
|
|
|
|
originalLevelID = req.body.originalLevelID
|
|
|
|
currentLevelID = req.body.levelID
|
|
|
|
requestLevelMajorVersion = parseInt(req.body.levelMajorVersion)
|
|
|
|
|
|
|
|
yetiGuru = {}
|
|
|
|
async.waterfall [
|
|
|
|
validatePermissions.bind(yetiGuru, req, requestSessionID)
|
|
|
|
fetchAndVerifyLevelType.bind(yetiGuru, currentLevelID)
|
|
|
|
fetchSessionObjectToSubmit.bind(yetiGuru, requestSessionID)
|
2016-05-05 16:22:30 -04:00
|
|
|
updateSessionToSubmit.bind(yetiGuru, req.user)
|
2015-12-06 07:36:41 -05:00
|
|
|
# Because there's some bug where the chained rankings don't work, and this is super slow, let's just not do this until we fix it.
|
|
|
|
#fetchInitialSessionsToRankAgainst.bind(yetiGuru, requestLevelMajorVersion, originalLevelID)
|
|
|
|
#generateAndSendTaskPairsToTheQueue
|
2015-08-13 14:17:38 -04:00
|
|
|
], (err, successMessageObject) ->
|
2015-09-07 21:00:48 -04:00
|
|
|
if err? then return errors.serverError res, "There was an error submitting the game to the queue: #{err}"
|
2015-08-15 08:38:47 -04:00
|
|
|
scoringUtils.sendResponseObject res, successMessageObject
|
2015-08-13 14:17:38 -04:00
|
|
|
|
|
|
|
|
|
|
|
validatePermissions = (req, sessionID, callback) ->
|
2015-09-07 21:00:48 -04:00
|
|
|
return callback 'You are unauthorized to submit that game to the simulator.' unless req.user?.get('email')
|
2015-08-13 14:17:38 -04:00
|
|
|
return callback null if req.user?.isAdmin()
|
|
|
|
|
|
|
|
findParameters = _id: sessionID
|
|
|
|
selectString = 'creator submittedCode code'
|
2015-09-07 21:00:48 -04:00
|
|
|
LevelSession.findOne(findParameters).select(selectString).lean().exec (err, retrievedSession) =>
|
2015-08-13 14:17:38 -04:00
|
|
|
if err? then return callback err
|
2015-09-07 21:00:48 -04:00
|
|
|
userHasPermissionToSubmitCode = retrievedSession.creator is req.user?.id
|
|
|
|
unless userHasPermissionToSubmitCode then return callback 'You are unauthorized to submit that game to the simulator.'
|
|
|
|
# Disabling this for now, since mirror matches submit different transpiled code for the same source code.
|
|
|
|
#alreadySubmitted = _.isEqual(retrievedSession.code, retrievedSession.submittedCode)
|
|
|
|
#unless alreadySubmitted then return callback 'You have already submitted that exact code for simulation.'
|
2015-08-13 14:17:38 -04:00
|
|
|
callback null
|
|
|
|
|
|
|
|
|
|
|
|
fetchAndVerifyLevelType = (levelID, cb) ->
|
|
|
|
Level.findOne(_id: levelID).select('type').lean().exec (err, levelWithType) ->
|
|
|
|
if err? then return cb err
|
|
|
|
if not levelWithType.type or not (levelWithType.type in ['ladder', 'hero-ladder', 'course-ladder']) then return cb 'Level isn\'t of type "ladder"'
|
|
|
|
cb null
|
|
|
|
|
|
|
|
fetchSessionObjectToSubmit = (sessionID, callback) ->
|
2016-05-05 16:22:30 -04:00
|
|
|
LevelSession.findOne({_id: sessionID}).select('team code leagues codeLanguage').exec (err, session) ->
|
2015-08-13 14:17:38 -04:00
|
|
|
callback err, session?.toObject()
|
|
|
|
|
2016-05-05 16:22:30 -04:00
|
|
|
updateSessionToSubmit = (user, sessionToUpdate, callback) ->
|
2015-08-13 14:17:38 -04:00
|
|
|
sessionUpdateObject =
|
|
|
|
submitted: true
|
|
|
|
submittedCode: sessionToUpdate.code
|
2016-05-05 16:22:30 -04:00
|
|
|
submittedCodeLanguage: sessionToUpdate.codeLanguage or 'python'
|
2015-08-13 14:17:38 -04:00
|
|
|
submitDate: new Date()
|
|
|
|
#meanStrength: 25 # Let's try not resetting the score on resubmission
|
2015-08-15 08:38:47 -04:00
|
|
|
standardDeviation: 25 / 3
|
2015-08-13 14:17:38 -04:00
|
|
|
#totalScore: 10 # Let's try not resetting the score on resubmission
|
|
|
|
numberOfWinsAndTies: 0
|
|
|
|
numberOfLosses: 0
|
|
|
|
isRanking: true
|
|
|
|
randomSimulationIndex: Math.random()
|
2015-08-15 08:38:47 -04:00
|
|
|
|
|
|
|
# Reset all league stats as well, and enter the session into any leagues the user is currently part of (not retroactive when joining new leagues)
|
|
|
|
leagueIDs = user.get('clans') or []
|
2015-11-18 17:02:45 -05:00
|
|
|
leagueIDs = leagueIDs.concat user.get('courseInstances') or []
|
2015-08-15 08:38:47 -04:00
|
|
|
leagueIDs = (leagueID + '' for leagueID in leagueIDs) # Make sure to save them as strings.
|
|
|
|
newLeagues = []
|
|
|
|
for leagueID in leagueIDs
|
2015-12-06 12:20:30 -05:00
|
|
|
league = _.clone(_.find(sessionToUpdate.leagues, leagueID: leagueID) ? leagueID: leagueID)
|
2015-08-15 08:38:47 -04:00
|
|
|
league.stats ?= {}
|
|
|
|
league.stats.standardDeviation = 25 / 3
|
|
|
|
league.stats.numberOfWinsAndTies = 0
|
|
|
|
league.stats.numberOfLosses = 0
|
2015-08-20 08:54:10 -04:00
|
|
|
league.stats.meanStrength ?= 25
|
|
|
|
league.stats.totalScore ?= 10
|
2015-12-06 12:20:30 -05:00
|
|
|
delete league.lastOpponentSubmitDate
|
2015-08-15 08:38:47 -04:00
|
|
|
newLeagues.push(league)
|
|
|
|
unless _.isEqual newLeagues, sessionToUpdate.leagues
|
|
|
|
sessionUpdateObject.leagues = sessionToUpdate.leagues = newLeagues
|
2015-08-13 14:17:38 -04:00
|
|
|
LevelSession.update {_id: sessionToUpdate._id}, sessionUpdateObject, (err, result) ->
|
|
|
|
callback err, sessionToUpdate
|
|
|
|
|
|
|
|
fetchInitialSessionsToRankAgainst = (levelMajorVersion, levelID, submittedSession, callback) ->
|
|
|
|
opposingTeam = scoringUtils.calculateOpposingTeam(submittedSession.team)
|
|
|
|
findParameters =
|
|
|
|
'level.original': levelID
|
|
|
|
'level.majorVersion': levelMajorVersion
|
|
|
|
submitted: true
|
|
|
|
team: opposingTeam
|
|
|
|
sortParameters = totalScore: 1
|
|
|
|
limitNumber = 1
|
|
|
|
query = LevelSession.aggregate [
|
|
|
|
{$match: findParameters}
|
|
|
|
{$sort: sortParameters}
|
|
|
|
{$limit: limitNumber}
|
|
|
|
]
|
|
|
|
|
|
|
|
query.exec (err, sessionToRankAgainst) ->
|
|
|
|
callback err, sessionToRankAgainst, submittedSession
|
|
|
|
|
|
|
|
generateAndSendTaskPairsToTheQueue = (sessionToRankAgainst, submittedSession, callback) ->
|
|
|
|
taskPairs = scoringUtils.generateTaskPairs(sessionToRankAgainst, submittedSession)
|
|
|
|
scoringUtils.sendEachTaskPairToTheQueue taskPairs, (taskPairError) ->
|
|
|
|
if taskPairError? then return callback taskPairError
|
|
|
|
#console.log 'Sent task pairs to the queue!'
|
|
|
|
#console.log taskPairs
|
|
|
|
callback null, {message: 'All task pairs were succesfully sent to the queue'}
|