Instrument user code problems

This commit is contained in:
Matt Lott 2014-08-14 11:55:43 -07:00
parent 719e64e85f
commit 9b79e2ca27
11 changed files with 185 additions and 4 deletions

View file

@ -0,0 +1,6 @@
CocoModel = require './CocoModel'
module.exports = class UserCodeProblem extends CocoModel
@className: 'UserCodeProblem'
@schema: require 'schemas/models/user_code_problem'
urlRoot: '/db/user.code.problem'

View file

@ -0,0 +1,25 @@
c = require './../schemas'
UserCodeProblemSchema = c.object {
title: 'User Code Problem'
description: 'Data for a problem in user code.'
}
_.extend UserCodeProblemSchema.properties,
creator: c.objectId(links: [{rel: 'extra', href: '/db/user/{($)}'}])
created: c.date({title: 'Created', readOnly: true})
code: String
codeSnippet: String
errHint: String
errId: String
errLevel: String
errMessage: String
errRange: []
errType: String
language: String
levelID: String
c.extendBasicProperties UserCodeProblemSchema, 'user.code.problem'
module.exports = UserCodeProblemSchema

View file

@ -1,20 +1,23 @@
ProblemAlertView = require './ProblemAlertView'
Range = ace.require('ace/range').Range
UserCodeProblem = require 'models/UserCodeProblem'
module.exports = class Problem
annotation: null
alertView: null
markerRange: null
constructor: (@aether, @aetherProblem, @ace, withAlert=false, withRange=false) ->
constructor: (@aether, @aetherProblem, @ace, withAlert=false, isCast=false, @levelID) ->
@buildAnnotation()
@buildAlertView() if withAlert
@buildMarkerRange() if withRange
@buildMarkerRange() if isCast
@saveUserCodeProblem() if isCast
destroy: ->
unless @alertView?.destroyed
@alertView?.$el?.remove()
@alertView?.destroy()
@removeMarkerRange()
@userCodeProblem.off() if @userCodeProblem
buildAnnotation: ->
return unless @aetherProblem.range
@ -46,3 +49,21 @@ module.exports = class Problem
@ace.getSession().removeMarker @markerRange.id
@markerRange.start.detach()
@markerRange.end.detach()
saveUserCodeProblem: () ->
@userCodeProblem = new UserCodeProblem()
@userCodeProblem.set 'code', @aether.raw
if @aetherProblem.range
rawLines = @aether.raw.split '\n'
errorLines = rawLines.slice @aetherProblem.range[0].row, @aetherProblem.range[1].row + 1
@userCodeProblem.set 'codeSnippet', errorLines.join '\n'
@userCodeProblem.set 'errHint', @aetherProblem.hint if @aetherProblem.hint
@userCodeProblem.set 'errId', @aetherProblem.id if @aetherProblem.id
@userCodeProblem.set 'errLevel', @aetherProblem.level if @aetherProblem.level
@userCodeProblem.set 'errMessage', @aetherProblem.message if @aetherProblem.message
@userCodeProblem.set 'errRange', @aetherProblem.range if @aetherProblem.range
@userCodeProblem.set 'errType', @aetherProblem.type if @aetherProblem.type
@userCodeProblem.set 'language', @aether.language.id if @aether.language?.id
@userCodeProblem.set 'levelID', @levelID if @levelID
@userCodeProblem.save()
null

View file

@ -19,6 +19,7 @@ module.exports = class Spell
@supermodel = options.supermodel
@skipProtectAPI = options.skipProtectAPI
@worker = options.worker
@levelID = options.levelID
p = options.programmableMethod
@languages = p.languages ? {}

View file

@ -414,7 +414,7 @@ module.exports = class SpellView extends CocoView
for aetherProblem, problemIndex in aether.getAllProblems()
continue if key = aetherProblem.userInfo?.key and key of seenProblemKeys
seenProblemKeys[key] = true if key
@problems.push problem = new Problem aether, aetherProblem, @ace, isCast and problemIndex is 0, isCast
@problems.push problem = new Problem aether, aetherProblem, @ace, isCast and problemIndex is 0, isCast, @spell.levelID
annotations.push problem.annotation if problem.annotation
@aceSession.setAnnotations annotations
@highlightCurrentLine aether.flow unless _.isEmpty aether.flow

View file

@ -132,6 +132,7 @@ module.exports = class TomeView extends CocoView
worker: @worker
language: language
spectateView: @options.spectateView
levelID: @options.levelID
for thangID, spellKeys of @thangSpells
thang = world.getThangByID thangID

View file

@ -8,6 +8,7 @@ module.exports.handlers =
'patch': 'patches/patch_handler'
'thang_type': 'levels/thangs/thang_type_handler'
'user': 'users/user_handler'
'user_code_problem': 'user_code_problems/user_code_problem_handler'
'user_remark': 'users/remarks/user_remark_handler'
'mail_sent': 'mail/sent/mail_sent_handler'
'achievement': 'achievements/achievement_handler'

View file

@ -28,7 +28,7 @@ module.exports.setup = (app) ->
return errors.unauthorized(res, 'Must have an identity to do anything with the db. Do you have cookies enabled?') unless req.user
try
moduleName = module.replace '.', '_'
moduleName = module.replace new RegExp('\\.', 'g'), '_'
name = handlers[moduleName]
handler = require('../' + name)
return handler.getLatestVersion(req, res, parts[1], parts[3]) if parts[2] is 'version'

View file

@ -0,0 +1,10 @@
mongoose = require 'mongoose'
plugins = require '../plugins/plugins'
UserCodeProblemSchema = new mongoose.Schema({
created:
type: Date
'default': Date.now
}, {strict: false})
module.exports = UserCodeProblem = mongoose.model('user.code.problem', UserCodeProblemSchema)

View file

@ -0,0 +1,25 @@
UserCodeProblem = require './UserCodeProblem'
Handler = require '../commons/Handler'
class UserCodeProblemHandler extends Handler
modelClass: UserCodeProblem
jsonSchema: require '../../app/schemas/models/user_code_problem'
editableProperties: [
'code'
'codeSnippet'
'errHint'
'errId'
'errLevel'
'errMessage'
'errRange'
'errType'
'language'
'levelID'
]
makeNewInstance: (req) ->
ucp = super(req)
ucp.set('creator', req.user._id)
ucp
module.exports = new UserCodeProblemHandler()

View file

@ -0,0 +1,91 @@
Problem = require 'views/play/level/tome/Problem'
describe 'Problem', ->
# boilerplate problem params
ace = {
getSession: -> {
getDocument: -> {
createAnchor: ->
}
addMarker: ->
}
}
aether = {
raw: "this.say('hi');\nthis.sad('bye');"
language: { id: 'javascript' }
}
aetherProblem = {
hint: 'did you mean say instead of sad?'
id: 'unknown_ReferenceError'
level: 'error'
message: 'Line 1: tmp2[tmp3] is not a function'
range: [
{ row: 1 }
{ row: 1 }
]
type: 'runtime'
}
levelID = 'awesome'
it 'save user code problem', ->
new Problem aether, aetherProblem, ace, false, true, levelID
expect(jasmine.Ajax.requests.count()).toBe(1)
request = jasmine.Ajax.requests.mostRecent()
expect(request.url).toEqual("/db/user.code.problem")
params = JSON.parse(request.params)
expect(params.code).toEqual(aether.raw)
expect(params.codeSnippet).toEqual("this.sad('bye');")
expect(params.errHint).toEqual(aetherProblem.hint)
expect(params.errId).toEqual(aetherProblem.id)
expect(params.errLevel).toEqual(aetherProblem.level)
expect(params.errMessage).toEqual(aetherProblem.message)
expect(params.errRange).toEqual(aetherProblem.range)
expect(params.errType).toEqual(aetherProblem.type)
expect(params.language).toEqual(aether.language.id)
expect(params.levelID).toEqual(levelID)
it 'save user code problem no range', ->
aetherProblem.range = null
new Problem aether, aetherProblem, ace, false, true, levelID
expect(jasmine.Ajax.requests.count()).toBe(1)
request = jasmine.Ajax.requests.mostRecent()
expect(request.url).toEqual("/db/user.code.problem")
params = JSON.parse(request.params)
expect(params.code).toEqual(aether.raw)
expect(params.errHint).toEqual(aetherProblem.hint)
expect(params.errId).toEqual(aetherProblem.id)
expect(params.errLevel).toEqual(aetherProblem.level)
expect(params.errMessage).toEqual(aetherProblem.message)
expect(params.errType).toEqual(aetherProblem.type)
expect(params.language).toEqual(aether.language.id)
expect(params.levelID).toEqual(levelID)
# Difference when no range
expect(params.codeSnippet).toBeUndefined()
expect(params.errRange).toBeUndefined()
it 'save user code problem multi-line snippet', ->
aether.raw = "this.say('hi');\nthis.sad\n('bye');"
aetherProblem.range = [ { row: 1 }, { row: 2 } ]
new Problem aether, aetherProblem, ace, false, true, levelID
expect(jasmine.Ajax.requests.count()).toBe(1)
request = jasmine.Ajax.requests.mostRecent()
expect(request.url).toEqual("/db/user.code.problem")
params = JSON.parse(request.params)
expect(params.code).toEqual(aether.raw)
expect(params.codeSnippet).toEqual("this.sad\n('bye');")
expect(params.errHint).toEqual(aetherProblem.hint)
expect(params.errId).toEqual(aetherProblem.id)
expect(params.errLevel).toEqual(aetherProblem.level)
expect(params.errMessage).toEqual(aetherProblem.message)
expect(params.errRange).toEqual(aetherProblem.range)
expect(params.errType).toEqual(aetherProblem.type)
expect(params.language).toEqual(aether.language.id)
expect(params.levelID).toEqual(levelID)