Explorar el Código

Mostly refactor post user route

sbkwgh hace 8 años
padre
commit
f61691437c
Se han modificado 4 ficheros con 105 adiciones y 116 borrados
  1. 7 0
      models/admin_token.js
  2. 69 2
      models/user.js
  3. 13 81
      routes/user.js
  4. 16 33
      test/user.js

+ 7 - 0
models/admin_token.js

@@ -6,6 +6,13 @@ module.exports = (sequelize, DataTypes) => {
 			type: DataTypes.STRING,
 			defaultValue () {
 				return crypto.randomBytes(64).toString('hex')
+			},
+			validate: {
+				isString (val) {
+					if(typeof val !== 'string') {
+						throw new sequelize.ValidationError('token must be a string')
+					}
+				}
 			}
 		}
 	}, {

+ 69 - 2
models/user.js

@@ -1,10 +1,28 @@
+let bcrypt = require('bcryptjs')
 let randomColor = require('randomcolor')
 
+const Errors = require('../lib/errors.js')
+
 module.exports = (sequelize, DataTypes) => {
 	let User = sequelize.define('User', {
 		username: {
 			type: DataTypes.STRING,
-			unique: true
+			unique: true,
+			validate: {
+				min: {
+					args: [1],
+					msg: 'username can\'t be less than 6 characters'
+				},
+				max: {
+					arg: 50,
+					msg: 'username can\'t be more than 50 characters'
+				},
+				isString (val) {
+					if(typeof val !== 'string') {
+						throw new sequelize.ValidationError('username must be a string')
+					}
+				}
+			}
 		},
 		description: DataTypes.TEXT,
 		color: {
@@ -13,7 +31,25 @@ module.exports = (sequelize, DataTypes) => {
 				return randomColor()
 			}
 		},
-		hash: DataTypes.STRING,
+		hash: {
+			type: DataTypes.STRING,
+			allowNull: false,
+			validate: {
+				min: {
+					arg: 6,
+					msg: 'password can\'t be less than 6 characters'
+				},
+				max: {
+					arg: 100,
+					msg: 'password can\'t be more than 100 characters'
+				},
+				isString (val) {
+					if(typeof val !== 'string') {
+						throw new sequelize.ValidationError('password must be a string')
+					}
+				}
+			}
+		},
 		admin: {
 			type: DataTypes.BOOLEAN,
 			defaultValue: false
@@ -35,6 +71,37 @@ module.exports = (sequelize, DataTypes) => {
 					where: { postNumber: { $gte: from } },
 					order: [['id', 'ASC']]
 				}]
+			},
+			async canBeAdmin (token) {
+				let { User, AdminToken } = sequelize.models
+				
+				let adminUser = await User.findOne({ where: {
+					admin: true
+				}})
+
+				if(adminUser) {
+					if(token) {
+						let adminToken = await AdminToken.findOne({ where: { token } })
+
+						if(adminToken && adminToken.isValid()) {
+							await adminToken.destroy()
+
+							return true
+						} else {
+							throw Errors.invalidToken
+						}
+					} else {
+						throw Errors.missingParameter('token')
+					}
+	
+				} else {
+					return true
+				}
+			}
+		},
+		hooks: {
+			async afterValidate(user) {
+				user.hash = await bcrypt.hash(user.hash, 12)
 			}
 		}
 	})

+ 13 - 81
routes/user.js

@@ -3,7 +3,7 @@ let express = require('express')
 let router = express.Router()
 
 const Errors = require('../lib/errors.js')
-let { User, Post, AdminToken, Thread, Category } = require('../models')
+let { User, Post, AdminToken, Thread, Category, Sequelize } = require('../models')
 let pagination = require('../lib/pagination.js')
 
 function setUserSession(req, res, username, UserId, admin) {
@@ -20,97 +20,29 @@ function setUserSession(req, res, username, UserId, admin) {
 	if(admin) { req.session.admin = true }
 }
 router.post('/', async (req, res) => {
-	let user, adminUser, hash, token
-	let validationErrors = []
-	let userParams = {}
-
 	try {
-		//Validations
-		if(req.body.username === undefined) {
-			validationErrors.push(Errors.missingParameter('username'))
-		} else {
-			if(typeof req.body.username !== 'string') {
-				validationErrors.push(Errors.invalidParameterType('username', 'string'))
-			} if(req.body.username.length < 6) {
-				validationErrors.push(Errors.parameterLengthTooSmall('username', 6))
-			} if(req.body.username.length > 50) {
-				validationErrors.push(Errors.parameterLengthTooLarge('username', 50))
-			}
+		let userParams = {
+			username: req.body.username,
+			hash: req.body.password,
+			admin: false
 		}
 
-		if(req.body.password === undefined) {
-			validationErrors.push(Errors.missingParameter('password'))
-		} else {
-			if(typeof req.body.password !== 'string') {
-				validationErrors.push(Errors.invalidParameterType('password', 'string'))
-			} if(req.body.password.length < 6) {
-				validationErrors.push(Errors.parameterLengthTooSmall('password', 6))
-			} if(req.body.password.length > 100) {
-				validationErrors.push(Errors.parameterLengthTooLarge('password', 100))
-			}
+		if(req.body.admin && await User.canBeAdmin(req.body.token)) {
+			userParams.admin = true
 		}
 
-		if(req.body.token !== undefined && typeof req.body.token !== 'string') {
-			validationErrors.push(Errors.invalidParameterType('token', 'string'))
-		}
-		if(req.body.admin !== undefined && typeof req.body.admin !== 'boolean') {
-			validationErrors.push(Errors.invalidParameterType('admin', 'boolean'))
-		}
-
-		if(validationErrors.length) throw Errors.VALIDATION_ERROR
-
-		if(req.body.admin && !req.body.token) {
-			adminUser = await User.findOne({ where: {
-				admin: true
-			}})
-
-			if(adminUser) {
-				validationErrors.push(Errors.missingParameter('token'))
-				throw Errors.VALIDATION_ERROR
-			} else {
-				
-				userParams.admin = true
-			}
-		} else if(req.body.admin && req.body.token) {
-			token = await AdminToken.findOne({ where: {
-				token: req.body.token
-			}})
-
-			if(token && token.isValid()) {
-				userParams.admin = true
-			} else {
-				throw Errors.invalidToken
-			}
-		}
-
-		hash = await bcrypt.hash(req.body.password, 12)
-
-		userParams.username = req.body.username
-		userParams.hash = hash
-		user = await User.create(userParams)
-
-		if(req.body.token) {
-			await token.destroy()
-		}
+		let user = await User.create(userParams)
 
 		setUserSession(req, res, user.username, user.id, userParams.admin)
-
 		res.json(user.toJSON())
-	} catch (err) {
-		if(err === Errors.VALIDATION_ERROR) {
-			res.status(400)
-			res.json({
-				errors: validationErrors
-			})
-		} else if(err.name === 'SequelizeUniqueConstraintError') {
+	} catch (e) {
+		if(e instanceof Sequelize.ValidationError) {
 			res.status(400)
-			res.json({
-				errors: [Errors.accountAlreadyCreated]
-			})
-		} else if (err = Errors.invalidToken) {
+			res.json(e)
+		} else if (e.name in Errors) {
 			res.status(401)
 			res.json({
-				errors: [Errors.invalidToken]
+				errors: [e]
 			})
 		} else {
 			console.log(e)

+ 16 - 33
test/user.js

@@ -76,7 +76,7 @@ describe('User', () => {
 					admin: true
 				})
 				.end((err, res) => {
-					res.should.have.status(400)
+					res.should.have.status(401)
 					res.should.be.json
 					res.body.should.have.property('errors')
 					res.body.errors.should.include.something.that.deep.equals(Errors.missingParameter('token'))
@@ -85,27 +85,6 @@ describe('User', () => {
 				})
 		})
 
-		it('should give an error if admin and token fields are not of the correct type ', (done) => {
-			chai.request(server)
-				.post('/api/v1/user')
-				.set('content-type', 'application/json')
-				.send({
-					username: 'adminaccount1',
-					password: 'password',
-					admin: 'not a boolean',
-					token: 123
-				})
-				.end((err, res) => {
-					res.should.have.status(400)
-					res.should.be.json
-					res.body.should.have.property('errors')
-					res.body.errors.should.include.something.that.deep.equals(Errors.invalidParameterType('admin', 'boolean'))
-					res.body.errors.should.include.something.that.deep.equals(Errors.invalidParameterType('token', 'string'))
-
-					done()
-				})
-		})
-
 		it('should give an error if an admin account is already created and token is invalid', (done) => {
 			chai.request(server)
 				.post('/api/v1/user')
@@ -188,7 +167,7 @@ describe('User', () => {
 					res.should.have.status(400)
 					res.should.be.json
 					res.body.should.have.property('errors')
-					res.body.errors.should.include.something.that.deep.equals(Errors.accountAlreadyCreated)
+					res.body.errors.should.contain.something.that.has.property('message', 'username must be unique')
 					
 					done()
 				})
@@ -203,9 +182,8 @@ describe('User', () => {
 				.end((err, res) => {
 					res.should.have.status(400)
 					res.should.be.json
-					res.body.should.have.property('errors')
-					res.body.errors.should.include.something.that.deep.equals(Errors.missingParameter('username'))
-					res.body.errors.should.include.something.that.deep.equals(Errors.missingParameter('password'))
+					res.body.should.have.property('errors')	
+					res.body.errors.should.contain.something.that.has.property('message', 'hash cannot be null')
 					
 					done()
 				})
@@ -223,8 +201,9 @@ describe('User', () => {
 					res.should.be.json
 					res.body.should.have.property('errors')
 					res.body.should.have.property('errors')
-					res.body.errors.should.include.something.that.deep.equals(Errors.invalidParameterType('username', 'string'))
-					res.body.errors.should.include.something.that.deep.equals(Errors.invalidParameterType('password', 'string'))
+
+					res.body.errors.should.contain.something.that.has.property('message', 'username must be a string')
+					res.body.errors.should.contain.something.that.has.property('message', 'password must be a string')
 					
 					done()
 				})
@@ -241,8 +220,11 @@ describe('User', () => {
 					res.should.have.status(400)
 					res.should.be.json
 					res.body.should.have.property('errors')
-					res.body.errors.should.contain.something.that.deep.equals(Errors.parameterLengthTooSmall('username', '6'))
-					res.body.errors.should.contain.something.that.deep.equals(Errors.parameterLengthTooSmall('password', '6'))
+
+					console.log(res.body)
+
+					res.body.errors.should.contain.something.that.has.property('message', 'username can\'t be less than 6 characters')
+					res.body.errors.should.contain.something.that.has.property('message', 'password can\'t be less than 6 characters')
 					
 					done()
 				})
@@ -259,9 +241,10 @@ describe('User', () => {
 					res.should.have.status(400)
 					res.should.be.json
 					res.body.should.have.property('errors')
-					res.body.errors.should.contain.something.that.deep.equals(Errors.parameterLengthTooLarge('username', '50'))
-					res.body.errors.should.contain.something.that.deep.equals(Errors.parameterLengthTooLarge('password', '100'))
-					
+
+					res.body.errors.should.contain.something.that.has.property('message', 'username can\'t be more than 50 characters')
+					res.body.errors.should.contain.something.that.has.property('message', 'password can\'t be more than 100 characters')
+
 					done()
 				})
 		})