mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-27 14:33:59 -04:00
refactor server http errors
- error.coffee centralize all http errors response - unauthorized = 401 and forbiden = 403
This commit is contained in:
parent
00780d630c
commit
fa218f7167
9 changed files with 67 additions and 116 deletions
|
@ -5,6 +5,7 @@ User = require('./models/User')
|
|||
UserHandler = require('./handlers/user')
|
||||
config = require '../server_config'
|
||||
nodemailer = require 'nodemailer'
|
||||
errors = require './errors'
|
||||
|
||||
module.exports.setupRoutes = (app) ->
|
||||
passport.serializeUser((user, done) -> done(null, user._id))
|
||||
|
@ -32,9 +33,7 @@ module.exports.setupRoutes = (app) ->
|
|||
passport.authenticate('local', (err, user, info) ->
|
||||
return next(err) if err
|
||||
if not user
|
||||
res.status(401)
|
||||
res.send([{message:info.message, property:info.property}])
|
||||
return res.end()
|
||||
return errors.unauthorized(res, [{message:info.message, property:info.property}])
|
||||
|
||||
req.logIn(user, (err) ->
|
||||
return next(err) if (err)
|
||||
|
@ -54,28 +53,25 @@ module.exports.setupRoutes = (app) ->
|
|||
req.logout()
|
||||
res.end()
|
||||
)
|
||||
|
||||
|
||||
app.post('/auth/reset', (req, res) ->
|
||||
unless req.body.email
|
||||
res.status(422)
|
||||
res.send([{message:'Need an email specified.', property:email}])
|
||||
return res.end()
|
||||
return errors.badInput(res, [{message:'Need an email specified.', property:email}])
|
||||
|
||||
User.findOne({emailLower:req.body.email.toLowerCase()}).exec((err, user) ->
|
||||
if not user
|
||||
res.status(404)
|
||||
res.send([{message:'not found.', property:'email'}])
|
||||
return res.end()
|
||||
return errors.notFound(res, [{message:'not found.', property:'email'}])
|
||||
|
||||
user.set('passwordReset', Math.random().toString(36).slice(2,7).toUpperCase())
|
||||
user.save (err) =>
|
||||
return returnServerError(res) if err
|
||||
return errors.serverError(res) if err
|
||||
if config.isProduction
|
||||
transport = createSMTPTransport()
|
||||
options = createMailOptions req.body.email, user.get('passwordReset')
|
||||
transport.sendMail options, (error, response) ->
|
||||
if error
|
||||
console.error "Error sending mail: #{error.message or error}"
|
||||
return returnServerError(res) if err
|
||||
return errors.serverError(res) if err
|
||||
else
|
||||
return res.end()
|
||||
else
|
||||
|
@ -102,9 +98,3 @@ createSMTPTransport = ->
|
|||
pass: config.mail.password
|
||||
authMethod: "LOGIN"
|
||||
smtpTransport
|
||||
|
||||
returnServerError = (res) ->
|
||||
res.status(500)
|
||||
res.send('Server error.')
|
||||
res.end()
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ winston = require 'winston'
|
|||
mongoose = require 'mongoose'
|
||||
Grid = require 'gridfs-stream'
|
||||
async = require 'async'
|
||||
errors = require './errors'
|
||||
|
||||
testing = '--unittest' in process.argv
|
||||
|
||||
|
@ -42,9 +43,7 @@ module.exports.setupRoutes = (app) ->
|
|||
catch error
|
||||
winston.error("Error trying db method #{req.route.method} route #{parts} from #{name}: #{error}")
|
||||
winston.error(error)
|
||||
res.status(404)
|
||||
res.write("Route #{req.path} not found.")
|
||||
res.end()
|
||||
errors.notFound(res, "Route #{req.path} not found.")
|
||||
|
||||
getSchema = (req, res, moduleName) ->
|
||||
try
|
||||
|
@ -55,6 +54,4 @@ getSchema = (req, res, moduleName) ->
|
|||
|
||||
catch error
|
||||
winston.error("Error trying to grab schema from #{name}: #{error}")
|
||||
res.status(404)
|
||||
res.write("Schema #{moduleName} not found.")
|
||||
res.end()
|
||||
errors.notFound(res, "Schema #{moduleName} not found.")
|
||||
|
|
|
@ -1,31 +1,35 @@
|
|||
|
||||
module.exports.notFound = (req, res, message) ->
|
||||
res.status(404)
|
||||
message = "Route #{req.path} not found." unless message
|
||||
res.write(message)
|
||||
res.end()
|
||||
|
||||
module.exports.badMethod = (res) ->
|
||||
res.status(405)
|
||||
res.send('Method not allowed.')
|
||||
res.end()
|
||||
module.exports.custom = (res, code=500, message='Internal Server Error') ->
|
||||
res.send code, message
|
||||
res.end
|
||||
|
||||
module.exports.badInput = (res) ->
|
||||
res.status(422)
|
||||
res.send('Bad post input.')
|
||||
res.end()
|
||||
module.exports.unauthorized = (res, message='Unauthorized') ->
|
||||
# TODO: The response MUST include a WWW-Authenticate header field
|
||||
res.send 401, message
|
||||
res.end
|
||||
|
||||
module.exports.conflict = (res) ->
|
||||
res.status(409)
|
||||
res.send('File exists.')
|
||||
res.end()
|
||||
module.exports.forbidden = (res, message='Forbidden') ->
|
||||
res.send 403, message
|
||||
res.end
|
||||
|
||||
module.exports.serverError = (res) ->
|
||||
res.status(500)
|
||||
res.send('Server error.')
|
||||
res.end()
|
||||
module.exports.notFound = (res, message='Not found.') ->
|
||||
res.send 404, message
|
||||
res.end
|
||||
|
||||
module.exports.unauthorized = (res) ->
|
||||
res.status(403)
|
||||
res.send('Unauthorized.')
|
||||
res.end()
|
||||
module.exports.badMethod = (res, message='Method Not Allowed') ->
|
||||
# TODO: The response MUST include an Allow header containing a list of valid methods for the requested resource
|
||||
res.send 405, message
|
||||
res.end
|
||||
|
||||
module.exports.conflict = (res, message='Conflict. File exists') ->
|
||||
res.send 409, message
|
||||
res.end
|
||||
|
||||
module.exports.badInput = (res, message='Unprocessable Entity. Bad Input.') ->
|
||||
res.send 422, message
|
||||
res.end
|
||||
|
||||
module.exports.serverError = (res, message='Internal Server Error') ->
|
||||
res.send 500, message
|
||||
res.end
|
||||
|
|
|
@ -3,12 +3,13 @@ Grid = require 'gridfs-stream'
|
|||
fs = require 'fs'
|
||||
request = require 'request'
|
||||
mongoose = require('mongoose')
|
||||
errors = require './errors'
|
||||
|
||||
module.exports.setupRoutes = (app) ->
|
||||
app.all '/file*', (req, res) ->
|
||||
return fileGet(req, res) if req.route.method is 'get'
|
||||
return filePost(req, res) if req.route.method is 'post'
|
||||
return returnBadMethod(res)
|
||||
return errors.badMethod(res)
|
||||
|
||||
|
||||
fileGet = (req, res) ->
|
||||
|
@ -27,16 +28,16 @@ fileGet = (req, res) ->
|
|||
|
||||
if isFolder
|
||||
Grid.gfs.collection('media').find query, (err, cursor) ->
|
||||
return returnServerError(res) if err
|
||||
return errors.serverError(res) if err
|
||||
results = cursor.toArray (err, results) ->
|
||||
return returnServerError(res) if err
|
||||
return errors.serverError(res) if err
|
||||
res.setHeader('Content-Type', 'text/json')
|
||||
res.send(results)
|
||||
res.end()
|
||||
|
||||
else
|
||||
Grid.gfs.collection('media').findOne query, (err, filedata) =>
|
||||
return returnNotFound(req, res) if not filedata
|
||||
return errors.notFound(res) if not filedata
|
||||
readstream = Grid.gfs.createReadStream({_id: filedata._id, root:'media'})
|
||||
if req.headers['if-modified-since'] is filedata.uploadDate
|
||||
res.status(304)
|
||||
|
@ -69,12 +70,13 @@ postFileSchema =
|
|||
required: ['filename', 'mimetype', 'path']
|
||||
|
||||
filePost = (req, res) ->
|
||||
return returnNotAllowed(req, res) unless req.user.isAdmin()
|
||||
return errors.forbidden(res) unless req.user.isAdmin()
|
||||
options = req.body
|
||||
tv4 = require('tv4').tv4
|
||||
valid = tv4.validate(options, postFileSchema)
|
||||
hasSource = options.url or options.postName or options.b64png
|
||||
return returnBadInput(res) if (not valid) or (not hasSource)
|
||||
# TODO : give tv4.error to badInput
|
||||
return errors.badInput(res) if (not valid) or (not hasSource)
|
||||
return saveURL(req, res) if options.url
|
||||
return saveFile(req, res) if options.postName
|
||||
return savePNG(req, res) if options.b64png
|
||||
|
@ -82,7 +84,7 @@ filePost = (req, res) ->
|
|||
saveURL = (req, res) ->
|
||||
options = createPostOptions(req)
|
||||
checkExistence options, res, req.body.force, (err) ->
|
||||
return returnServerError(res) if err
|
||||
return errors.serverError(res) if err
|
||||
writestream = Grid.gfs.createWriteStream(options)
|
||||
request(req.body.url).pipe(writestream)
|
||||
handleStreamEnd(res, writestream)
|
||||
|
@ -100,7 +102,7 @@ saveFile = (req, res) ->
|
|||
savePNG = (req, res) ->
|
||||
options = createPostOptions(req)
|
||||
checkExistence options, res, req.body.force, (err) ->
|
||||
return returnServerError(res) if err
|
||||
return errors.serverError(res) if err
|
||||
writestream = Grid.gfs.createWriteStream(options)
|
||||
img = new Buffer(req.body.b64png, 'base64')
|
||||
streamBuffers = require 'stream-buffers'
|
||||
|
@ -116,13 +118,13 @@ checkExistence = (options, res, force, done) ->
|
|||
}
|
||||
Grid.gfs.collection('media').find(q).toArray (err, files) ->
|
||||
if files.length and not force
|
||||
returnConflict(res)
|
||||
errors.conflict(res)
|
||||
done(true)
|
||||
else if files.length
|
||||
q = { _id: files[0]._id }
|
||||
q.root = 'media'
|
||||
Grid.gfs.remove q, (err) ->
|
||||
return returnServerError(res) if err
|
||||
return errors.serverError(res) if err
|
||||
done()
|
||||
else
|
||||
done()
|
||||
|
@ -133,7 +135,7 @@ handleStreamEnd = (res, stream) ->
|
|||
res.end()
|
||||
|
||||
stream.on 'error', ->
|
||||
return returnServerError(res)
|
||||
return errors.serverError(res)
|
||||
|
||||
CHUNK_SIZE = 1024*256
|
||||
|
||||
|
@ -159,35 +161,3 @@ createPostOptions = (req) ->
|
|||
options.metadata.description = req.body.description if req.body.description?
|
||||
|
||||
options
|
||||
|
||||
returnNotAllowed = (req, res, message) ->
|
||||
res.status(403)
|
||||
message = "Can't do that, Dave." unless message
|
||||
res.write(message)
|
||||
res.end()
|
||||
|
||||
returnNotFound = (req, res, message) ->
|
||||
res.status(404)
|
||||
message = "Route #{req.path} not found." unless message
|
||||
res.write(message)
|
||||
res.end()
|
||||
|
||||
returnBadMethod = (res) ->
|
||||
res.status(405)
|
||||
res.send('Method not allowed.')
|
||||
res.end()
|
||||
|
||||
returnBadInput = (res) ->
|
||||
res.status(422)
|
||||
res.send('Bad post input.')
|
||||
res.end()
|
||||
|
||||
returnConflict = (res) ->
|
||||
res.status(409)
|
||||
res.send('File exists.')
|
||||
res.end()
|
||||
|
||||
returnServerError = (res) ->
|
||||
res.status(500)
|
||||
res.send('Server error.')
|
||||
res.end()
|
|
@ -12,7 +12,7 @@ folderGet = (req, res) ->
|
|||
folder = req.path[7..]
|
||||
userfolder = "/user-#{req.user.id}/"
|
||||
folder = userfolder if folder is '/me/'
|
||||
return errors.unauthorized(res) unless (folder is userfolder) or (req.user.isAdmin())
|
||||
return errors.forbidden(res) unless (folder is userfolder) or (req.user.isAdmin())
|
||||
|
||||
mongoose.connection.db.collection 'media.files', (errors, collection) ->
|
||||
collection.find({'metadata.path': folder}).toArray (err, results) ->
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
async = require 'async'
|
||||
mongoose = require('mongoose')
|
||||
Grid = require 'gridfs-stream'
|
||||
errors = require '../errors'
|
||||
|
||||
module.exports = class Handler
|
||||
# subclasses should override these properties
|
||||
|
@ -38,17 +39,14 @@ module.exports = class Handler
|
|||
props
|
||||
|
||||
# sending functions
|
||||
sendUnauthorizedError: (res) -> @sendError(res, 403, "Unauthorized.")
|
||||
sendNotFoundError: (res) -> @sendError(res, 404, 'Resource not found.')
|
||||
sendMethodNotAllowed: (res) -> @sendError(res, 405, 'Method not allowed.')
|
||||
sendBadInputError: (res, message) -> @sendError(res, 422, message)
|
||||
sendDatabaseError: (res, err) -> @sendError(res, 500, 'Database error.')
|
||||
sendUnauthorizedError: (res) -> errors.forbidden(res) #TODO: rename sendUnauthorizedError to sendForbiddenError
|
||||
sendNotFoundError: (res) -> errors.notFound(res)
|
||||
sendMethodNotAllowed: (res) -> errors.badMethod(res)
|
||||
sendBadInputError: (res, message) -> errors.badInput(res, message)
|
||||
sendDatabaseError: (res, err) -> errors.serverError(res, 'Database error, ' + err)
|
||||
|
||||
sendError: (res, code, message) ->
|
||||
console.warn "Sending an error code", code, message
|
||||
res.status(code)
|
||||
res.send(message)
|
||||
res.end()
|
||||
errors.custom(res, code, message)
|
||||
|
||||
sendSuccess: (res, message) ->
|
||||
res.send(message)
|
||||
|
|
|
@ -41,8 +41,7 @@ LevelHandler = class LevelHandler extends Handler
|
|||
Session.findOne(sessionQuery).exec (err, doc) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
if doc
|
||||
res.send(doc)
|
||||
res.end()
|
||||
@sendSuccess(res, doc)
|
||||
return
|
||||
|
||||
initVals = sessionQuery
|
||||
|
@ -71,8 +70,7 @@ LevelHandler = class LevelHandler extends Handler
|
|||
Feedback.findOne(feedbackQuery).exec (err, doc) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) unless doc?
|
||||
res.send(doc)
|
||||
res.end()
|
||||
@sendSuccess(res, doc)
|
||||
return
|
||||
|
||||
postEditableProperties: ['name']
|
||||
|
|
|
@ -139,8 +139,7 @@ UserHandler = class UserHandler extends Handler
|
|||
req.user.set('signedCLA', doc.created)
|
||||
req.user.save (err) ->
|
||||
return @sendDatabaseError(res, err) if err
|
||||
res.send({result:'success'})
|
||||
res.end()
|
||||
@sendSuccess(res, {result:'success'})
|
||||
|
||||
module.exports = new UserHandler()
|
||||
|
||||
|
@ -157,17 +156,14 @@ module.exports.setupMiddleware = (app) ->
|
|||
loginUser = (req, res, user, send=true, next=null) ->
|
||||
user.save((err) ->
|
||||
if err
|
||||
res.status(500)
|
||||
return res.end()
|
||||
return @sendDatabaseError(res, err)
|
||||
|
||||
req.logIn(user, (err) ->
|
||||
if err
|
||||
res.status(500)
|
||||
return res.end()
|
||||
return @sendDatabaseError(res, err)
|
||||
|
||||
if send
|
||||
res.send(user)
|
||||
return res.end()
|
||||
return @sendSuccess(res, user)
|
||||
next() if next
|
||||
)
|
||||
)
|
||||
|
|
|
@ -92,8 +92,6 @@ ghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghlfarghlarghl
|
|||
req = request.put getURL('/db/user'),
|
||||
(err, res) ->
|
||||
expect(res.statusCode).toBe(404)
|
||||
expect(res.body).toBe('Resource not found.')
|
||||
done()
|
||||
done()
|
||||
form = req.form()
|
||||
form.append('_id', '513108d4cb8b610000000004')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue