codecombat/server/user_code_problems/user_code_problem_handler.coffee

91 lines
3.2 KiB
CoffeeScript

UserCodeProblem = require './UserCodeProblem'
Handler = require '../commons/Handler'
utils = require '../lib/utils'
class UserCodeProblemHandler extends Handler
modelClass: UserCodeProblem
jsonSchema: require '../../app/schemas/models/user_code_problem'
editableProperties: [
'code'
'codeSnippet'
'errHint'
'errId'
'errLevel'
'errMessage'
'errMessageNoLineInfo'
'errRange'
'errType'
'language'
'levelID'
]
makeNewInstance: (req) ->
ucp = super(req)
ucp.set('creator', req.user._id)
ucp
hasAccess: (req) ->
return true if req.user?.isAdmin()
return true if req.method.toLowerCase() is 'post'
false
getByRelationship: (req, res, args...) ->
return @sendForbiddenError res unless @hasAccess req
return @getCommonLevelProblemsBySlug(req, res) if args[1] is 'common_problems'
super(arguments...)
getCommonLevelProblemsBySlug: (req, res) ->
# Returns an ordered array of common user code problems with: language, message, hint, count
# Parameters:
# slug - level slug
# startDay - Inclusive, optional, e.g. '2014-12-14'
# endDay - Exclusive, optional, e.g. '2014-12-16'
levelSlug = req.query.slug or req.body.slug
startDay = req.query.startDay or req.body.startDay
endDay = req.query.endDay or req.body.endDay
return @sendSuccess res, [] unless levelSlug?
# Cache results for 1 day
@commonLevelProblemsCache ?= {}
@commonLevelProblemsCachedSince ?= new Date()
if (new Date()) - @commonLevelProblemsCachedSince > 86400 * 1000 # Dumb cache expiration
@commonLevelProblemsCache = {}
@commonLevelProblemsCachedSince = new Date()
cacheKey = levelSlug
cacheKey += 's' + startDay if startDay?
cacheKey += 'e' + endDay if endDay?
return @sendSuccess res, commonProblems if commonProblems = @commonLevelProblemsCache[cacheKey]
# Build query
match = if startDay? or endDay? then {$match: {$and: []}} else {$match: {}}
match["$match"]["$and"].push _id: {$gte: utils.objectIdFromTimestamp(startDay + "T00:00:00.000Z")} if startDay?
match["$match"]["$and"].push _id: {$lt: utils.objectIdFromTimestamp(endDay + "T00:00:00.000Z")} if endDay?
group = {"$group": {"_id": {"errMessage": "$errMessageNoLineInfo", "errHint": "$errHint", "language": "$language", "levelID": "$levelID"}, "count": {"$sum": 1}}}
sort = { $sort : { "_id.levelID": 1, count : -1, "_id.language": 1 } }
query = UserCodeProblem.aggregate match, group, sort
query.exec (err, data) =>
if err? then return @sendDatabaseError res, err
# Build per-level common problem lists
commonProblems = {}
for item in data
levelID = item._id.levelID
commonProblems[levelID] ?= []
commonProblems[levelID].push
language: item._id.language
message: item._id.errMessage
hint: item._id.errHint
count: item.count
# Cache all the levels
for levelID of commonProblems
cacheKey = levelID
cacheKey += 's' + startDay if startDay?
cacheKey += 'e' + endDay if endDay?
@commonLevelProblemsCache[cacheKey] = commonProblems[levelID]
@sendSuccess res, commonProblems[levelSlug]
module.exports = new UserCodeProblemHandler()