mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 23:58:02 -05:00
Bunch of server changes, mainly adding all the JSON schema validation and fixing tests.
This commit is contained in:
parent
17c1bb7344
commit
c382889748
17 changed files with 45 additions and 22 deletions
|
@ -46,7 +46,7 @@
|
|||
"mongoose": "3.8.x",
|
||||
"mongoose-text-search": "~0.0.2",
|
||||
"request": "2.12.x",
|
||||
"tv4": "1.0.11",
|
||||
"tv4": "1.0.x",
|
||||
"lodash": "~2.0.0",
|
||||
"underscore.string": "2.3.x",
|
||||
"async": "0.2.x",
|
||||
|
@ -56,7 +56,7 @@
|
|||
"graceful-fs": "~2.0.1",
|
||||
"node-force-domain": "~0.1.0",
|
||||
"mailchimp-api": "2.0.x",
|
||||
"express-useragent": "~0.0.9",
|
||||
"express-useragent": "~0.0.9",
|
||||
"gridfs-stream": "0.4.x",
|
||||
"stream-buffers": "0.2.x",
|
||||
"sendwithus": "2.0.x",
|
||||
|
|
|
@ -4,6 +4,7 @@ Handler = require('../commons/Handler')
|
|||
ArticleHandler = class ArticleHandler extends Handler
|
||||
modelClass: Article
|
||||
editableProperties: ['body', 'name', 'i18n']
|
||||
jsonSchema: require './article_schema'
|
||||
|
||||
hasAccess: (req) ->
|
||||
req.method is 'GET' or req.user?.isAdmin()
|
||||
|
|
|
@ -48,6 +48,7 @@ module.exports = class Handler
|
|||
sendMethodNotAllowed: (res) -> errors.badMethod(res)
|
||||
sendBadInputError: (res, message) -> errors.badInput(res, message)
|
||||
sendDatabaseError: (res, err) ->
|
||||
return @sendError(res, err.code, err.response) if err.response and err.code
|
||||
log.error "Database error, #{err}"
|
||||
errors.serverError(res, 'Database error, ' + err)
|
||||
|
||||
|
@ -203,10 +204,9 @@ module.exports = class Handler
|
|||
return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body)
|
||||
return @sendBadInputError(res, 'id should not be included.') if req.body._id
|
||||
return @sendUnauthorizedError(res) unless @hasAccess(req)
|
||||
validation = @validateDocumentInput(req.body)
|
||||
return @sendBadInputError(res, validation.errors) unless validation.valid
|
||||
document = @makeNewInstance(req)
|
||||
@saveChangesToDocument req, document, (err) =>
|
||||
return @sendBadInputError(res, err.errors) if err?.valid is false
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, @formatEntity(req, document))
|
||||
|
||||
|
@ -220,13 +220,11 @@ module.exports = class Handler
|
|||
return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body)
|
||||
return @sendBadInputError(res, 'id should not be included.') if req.body._id
|
||||
return @sendUnauthorizedError(res) unless @hasAccess(req)
|
||||
validation = @validateDocumentInput(req.body)
|
||||
return @sendBadInputError(res, validation.errors) unless validation.valid
|
||||
document = @makeNewInstance(req)
|
||||
document.set('original', document._id)
|
||||
document.set('creator', req.user._id)
|
||||
@saveChangesToDocument req, document, (err) =>
|
||||
return @sendBadInputError(res, err.response) if err?.response
|
||||
return @sendBadInputError(res, err.errors) if err?.valid is false
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, @formatEntity(req, document))
|
||||
|
||||
|
@ -245,8 +243,6 @@ module.exports = class Handler
|
|||
return @sendBadInputError(res, 'This entity is not versioned') unless @modelClass.schema.uses_coco_versions
|
||||
return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body)
|
||||
return @sendUnauthorizedError(res) unless @hasAccess(req)
|
||||
validation = @validateDocumentInput(req.body)
|
||||
return @sendBadInputError(res, validation.errors) unless validation.valid
|
||||
@getDocumentForIdOrSlug req.body._id, (err, parentDocument) =>
|
||||
return @sendBadInputError(res, 'Bad id.') if err and err.name is 'CastError'
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
@ -261,6 +257,8 @@ module.exports = class Handler
|
|||
delete updatedObject[prop]
|
||||
delete updatedObject._id
|
||||
major = req.body.version?.major
|
||||
validation = @validateDocumentInput(updatedObject)
|
||||
return @sendBadInputError(res, validation.errors) unless validation.valid
|
||||
|
||||
done = (err, newDocument) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
|
|
@ -6,6 +6,7 @@ module.exports.handlers =
|
|||
'level_feedback': 'levels/feedbacks/level_feedback_handler'
|
||||
'level_session': 'levels/sessions/level_session_handler'
|
||||
'level_system': 'levels/systems/level_system_handler'
|
||||
'patch': 'patches/patch_handler'
|
||||
'thang_type': 'levels/thangs/thang_type_handler'
|
||||
'user': 'users/user_handler'
|
||||
|
||||
|
@ -19,6 +20,7 @@ module.exports.schemas =
|
|||
'level_session': 'levels/sessions/level_session_schema'
|
||||
'level_system': 'levels/systems/level_system_schema'
|
||||
'metaschema': 'commons/metaschema'
|
||||
'patch': 'patches/patch_schema'
|
||||
'thang_component': 'levels/thangs/thang_component_schema'
|
||||
'thang_type': 'levels/thangs/thang_type_schema'
|
||||
'user': 'users/user_schema'
|
||||
|
|
|
@ -13,7 +13,7 @@ me.object = (ext, props) -> combine {type: 'object', additionalProperties: false
|
|||
me.array = (ext, items) -> combine {type: 'array', items: items or {}}, ext
|
||||
me.shortString = (ext) -> combine({type: 'string', maxLength: 100}, ext)
|
||||
me.pct = (ext) -> combine({type: 'number', maximum: 1.0, minimum: 0.0}, ext)
|
||||
me.date = (ext) -> combine({type: 'string', format: 'date-time'}, ext)
|
||||
me.date = (ext) -> combine({type: ['object', 'string'], format: 'date-time'}, ext)
|
||||
# should just be string (Mongo ID), but sometimes mongoose turns them into objects representing those, so we are lenient
|
||||
me.objectId = (ext) -> schema = combine({type: ['object', 'string'] }, ext)
|
||||
|
||||
|
@ -51,7 +51,18 @@ basicProps = (linkFragment) ->
|
|||
me.extendBasicProperties = (schema, linkFragment) ->
|
||||
schema.properties = {} unless schema.properties?
|
||||
_.extend(schema.properties, basicProps(linkFragment))
|
||||
|
||||
# PATCHABLE
|
||||
|
||||
patchableProps = ->
|
||||
patches: me.array({title:'Patches'}, {
|
||||
_id: me.objectId(links: [{rel: "db", href: "/db/patch/{($)}"}], title: "Patch ID", description: "A reference to the patch.")
|
||||
status: { enum: ['pending', 'accepted', 'rejected', 'cancelled']}
|
||||
})
|
||||
|
||||
me.extendPatchableProperties = (schema) ->
|
||||
schema.properties = {} unless schema.properties?
|
||||
_.extend(schema.properties, patchableProps())
|
||||
|
||||
# NAMED
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ Handler = require('../../commons/Handler')
|
|||
|
||||
LevelComponentHandler = class LevelComponentHandler extends Handler
|
||||
modelClass: LevelComponent
|
||||
jsonSchema: require './level_component_schema'
|
||||
editableProperties: [
|
||||
'system'
|
||||
'description'
|
||||
|
|
|
@ -4,6 +4,7 @@ Handler = require('../../commons/Handler')
|
|||
class LevelFeedbackHandler extends Handler
|
||||
modelClass: LevelFeedback
|
||||
editableProperties: ['rating', 'review', 'level', 'levelID', 'levelName']
|
||||
jsonSchema: require './level_feedback_schema'
|
||||
|
||||
makeNewInstance: (req) ->
|
||||
feedback = super(req)
|
||||
|
|
|
@ -8,6 +8,7 @@ mongoose = require('mongoose')
|
|||
|
||||
LevelHandler = class LevelHandler extends Handler
|
||||
modelClass: Level
|
||||
jsonSchema: require './level_schema'
|
||||
editableProperties: [
|
||||
'description'
|
||||
'documentation'
|
||||
|
|
|
@ -9,6 +9,7 @@ class LevelSessionHandler extends Handler
|
|||
editableProperties: ['multiplayer', 'players', 'code', 'completed', 'state',
|
||||
'levelName', 'creatorName', 'levelID', 'screenshot',
|
||||
'chat', 'teamSpells', 'submitted', 'unsubscribed']
|
||||
jsonSchema: require './level_session_schema'
|
||||
|
||||
getByRelationship: (req, res, args...) ->
|
||||
return @getActiveSessions req, res if args.length is 2 and args[1] is 'active'
|
||||
|
|
|
@ -13,6 +13,7 @@ LevelSystemHandler = class LevelSystemHandler extends Handler
|
|||
'configSchema'
|
||||
]
|
||||
postEditableProperties: ['name']
|
||||
jsonSchema: require './level_system_schema'
|
||||
|
||||
getEditableProperties: (req, document) ->
|
||||
props = super(req, document)
|
||||
|
|
|
@ -3,6 +3,7 @@ Handler = require('../../commons/Handler')
|
|||
|
||||
ThangTypeHandler = class ThangTypeHandler extends Handler
|
||||
modelClass: ThangType
|
||||
jsonSchema: require './thang_type_schema'
|
||||
editableProperties: [
|
||||
'name',
|
||||
'raw',
|
||||
|
|
|
@ -42,6 +42,7 @@ module.exports.setup = (app) ->
|
|||
catch error
|
||||
log.error("Error trying db method #{req.route.method} route #{parts} from #{name}: #{error}")
|
||||
log.error(error)
|
||||
log.error(error.stack)
|
||||
errors.notFound(res, "Route #{req.path} not found.")
|
||||
|
||||
getSchema = (req, res, moduleName) ->
|
||||
|
@ -49,7 +50,7 @@ getSchema = (req, res, moduleName) ->
|
|||
name = schemas[moduleName.replace '.', '_']
|
||||
schema = require('../' + name)
|
||||
|
||||
res.send(schema)
|
||||
res.send(JSON.stringify(schema, null, '\t'))
|
||||
res.end()
|
||||
|
||||
catch error
|
||||
|
|
|
@ -78,11 +78,8 @@ unittest.getUser = (email, password, done, force) ->
|
|||
req = request.post(getURL('/db/user'), (err, response, body) ->
|
||||
throw err if err
|
||||
User.findOne({email:email}).exec((err, user) ->
|
||||
if password is '80yqxpb38j'
|
||||
user.set('permissions', [ 'admin' ])
|
||||
user.save (err) ->
|
||||
wrapUpGetUser(email, user, done)
|
||||
else
|
||||
user.set('permissions', if password is '80yqxpb38j' then [ 'admin' ] else [])
|
||||
user.save (err) ->
|
||||
wrapUpGetUser(email, user, done)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -55,7 +55,7 @@ describe '/auth/login', ->
|
|||
it 'rejects wrong passwords', (done) ->
|
||||
req = request.post(urlLogin, (error, response) ->
|
||||
expect(response.statusCode).toBe(401)
|
||||
expect(response.body.indexOf("wrong, wrong")).toBeGreaterThan(-1)
|
||||
expect(response.body.indexOf("wrong")).toBeGreaterThan(-1)
|
||||
done()
|
||||
)
|
||||
form = req.form()
|
||||
|
@ -96,7 +96,6 @@ describe '/auth/reset', ->
|
|||
it 'resets user password', (done) ->
|
||||
req = request.post(urlReset, (error, response) ->
|
||||
expect(response).toBeDefined()
|
||||
console.log 'status code is', response.statusCode
|
||||
expect(response.statusCode).toBe(200)
|
||||
expect(response.body).toBeDefined()
|
||||
passwordReset = response.body
|
||||
|
|
|
@ -6,6 +6,9 @@ describe 'Level', ->
|
|||
name: "King's Peak 3"
|
||||
description: 'Climb a mountain.'
|
||||
permissions: simplePermissions
|
||||
scripts: []
|
||||
thangs: []
|
||||
documentation: {specificArticles:[], generalArticles:[]}
|
||||
|
||||
urlLevel = '/db/level'
|
||||
|
||||
|
|
|
@ -3,11 +3,14 @@ require '../common'
|
|||
describe 'LevelComponent', ->
|
||||
|
||||
component =
|
||||
name:'Bashes Everything'
|
||||
name:'BashesEverything'
|
||||
description:'Makes the unit uncontrollably bash anything bashable, using the bash system.'
|
||||
code: 'bash();'
|
||||
language: 'javascript'
|
||||
language: 'coffeescript'
|
||||
permissions:simplePermissions
|
||||
propertyDocumentation: []
|
||||
system: 'ai'
|
||||
dependencies: []
|
||||
|
||||
components = {}
|
||||
|
||||
|
@ -45,7 +48,7 @@ describe 'LevelComponent', ->
|
|||
it 'have a unique name.', (done) ->
|
||||
loginAdmin ->
|
||||
request.post {uri:url, json:component}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(422)
|
||||
expect(res.statusCode).toBe(409)
|
||||
done()
|
||||
|
||||
it 'can be read by an admin.', (done) ->
|
||||
|
|
|
@ -11,6 +11,8 @@ describe 'LevelSystem', ->
|
|||
"""
|
||||
language: 'coffeescript'
|
||||
permissions:simplePermissions
|
||||
dependencies: []
|
||||
propertyDocumentation: []
|
||||
|
||||
systems = {}
|
||||
|
||||
|
@ -48,7 +50,7 @@ describe 'LevelSystem', ->
|
|||
it 'have a unique name.', (done) ->
|
||||
loginAdmin ->
|
||||
request.post {uri:url, json:system}, (err, res, body) ->
|
||||
expect(res.statusCode).toBe(422)
|
||||
expect(res.statusCode).toBe(409)
|
||||
done()
|
||||
|
||||
it 'can be read by an admin.', (done) ->
|
||||
|
|
Loading…
Reference in a new issue