Files
bch-dex/src/modules/users/controller.js
T

328 lines
9.0 KiB
JavaScript

const User = require('../../models/users')
let _this
class UserController {
constructor () {
_this = this
this.User = User
}
/**
* @api {post} /users Create a new user
* @apiPermission user
* @apiName CreateUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "email": "email@format.com", "password": "secretpasas" } }' localhost:5001/users
*
* @apiParam {Object} user User object (required)
* @apiParam {String} user.email Email.
* @apiParam {String} user.password Password.
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} user.type User type (admin or user)
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.username User username
* @apiSuccess {String} users.email User email
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "user": {
* "_id": "56bd1da600a526986cf65c80"
* "name": "John Doe"
* "email": "email@format.com"
* }
* }
*
* @apiError UnprocessableEntity Missing required parameters
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 422 Unprocessable Entity
* {
* "status": 422,
* "error": "Unprocessable Entity"
* }
*/
async createUser (ctx) {
const userObj = ctx.request.body.user
try {
/*
* ERROR HANDLERS
*
*/
// Required property
if (!userObj.email || typeof userObj.email !== 'string') {
throw new Error("Property 'email' must be a string!")
}
// This validation is not permissive to different TLDs like this one:
// someone@somewhere.link. Removing it until it can be updated.
// const isEmail = await _this.validateEmail(user.email)
// if (!isEmail) {
// throw new Error("Property 'email' must be email format!")
// }
if (!userObj.password || typeof userObj.password !== 'string') {
throw new Error("Property 'password' must be a string!")
}
if (userObj.name && typeof userObj.name !== 'string') {
throw new Error("Property 'name' must be a string!")
}
const user = new _this.User(userObj)
// Enforce default value of 'user'
user.type = 'user'
await user.save()
const token = user.generateToken()
const response = user.toJSON()
delete response.password
ctx.body = {
user: response,
token
}
} catch (err) {
ctx.throw(422, err.message)
}
}
/**
* @api {get} /users Get all users
* @apiPermission user
* @apiName GetUsers
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/users
*
* @apiSuccess {Object[]} users Array of user objects
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} user.type User type (admin or user)
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.username User username
* @apiSuccess {String} users.email User email
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "users": [{
* "_id": "56bd1da600a526986cf65c80"
* "name": "John Doe"
* "email": "email@format.com"
* }]
* }
*
* @apiUse TokenError
*/
async getUsers (ctx) {
try {
const users = await _this.User.find({}, '-password')
ctx.body = { users }
} catch (error) {
ctx.throw(404)
}
}
/**
* @api {get} /users/:id Get user by id
* @apiPermission user
* @apiName GetUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/users/56bd1da600a526986cf65c80
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} user.type User type (admin or user)
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.username User username
* @apiSuccess {String} users.email User email
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "user": {
* "_id": "56bd1da600a526986cf65c80"
* "name": "John Doe"
* "email": "email@format.com"
* }
* }
*
* @apiUse TokenError
*/
async getUser (ctx, next) {
try {
const user = await _this.User.findById(ctx.params.id, '-password')
if (!user) {
ctx.throw(404)
}
ctx.body = {
user
}
} catch (err) {
// Handle different error types.
if (
err === 404 ||
err.name === 'CastError' ||
err.message.toString().includes('Not Found')
) {
ctx.throw(404)
}
ctx.throw(500)
}
if (next) {
return next()
}
}
/**
* @api {put} /users/:id Update a user
* @apiPermission user
* @apiName UpdateUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X PUT -d '{ "user": { "name": "Cool new Name" } }' localhost:5000/users/56bd1da600a526986cf65c80
*
* @apiParam {Object} user User object (required)
* @apiParam {String} user.name Name.
* @apiParam {String} user.email Email.
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} user.type User type (admin or user)
* @apiSuccess {String} users.name Updated name
* @apiSuccess {String} users.username Updated username
* @apiSuccess {String} users.email Updated email
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "user": {
* "_id": "56bd1da600a526986cf65c80"
* "name": "Cool new name"
* "email": "email@format.com"
* }
* }
*
* @apiError UnprocessableEntity Missing required parameters
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 422 Unprocessable Entity
* {
* "status": 422,
* "error": "Unprocessable Entity"
* }
*
* @apiUse TokenError
*/
async updateUser (ctx) {
// Values obtain from user request.
// This variable is intended to validate the properties
// sent by the client
const userObj = ctx.request.body.user
const user = ctx.body.user
try {
/*
* ERROR HANDLERS
*
*/
// Required property
if (userObj.email && typeof userObj.email !== 'string') {
throw new Error("Property 'email' must be a string!")
}
const isEmail = await _this.validateEmail(userObj.email)
if (userObj.email && !isEmail) {
throw new Error("Property 'email' must be email format!")
}
if (userObj.password && typeof userObj.password !== 'string') {
throw new Error("Property 'password' must be a string!")
}
if (userObj.name && typeof userObj.name !== 'string') {
throw new Error("Property 'name' must be a string!")
}
if (userObj.projects && !Array.isArray(userObj.projects)) {
throw new Error("Property 'projects' must be a Array!")
}
// Save a copy of the original user type.
const userType = user.type
// If user type property is sent by the client
if (userObj.type) {
if (typeof userObj.type !== 'string') {
throw new Error("Property 'type' must be a string!")
}
// TODO: Here we can validate the user types allowed
// Unless the calling user is an admin, they can not change the user type.
if (userType !== 'admin') {
throw new Error("Property 'type' can only be changed by Admin user")
}
}
Object.assign(user, ctx.request.body.user)
await user.save()
ctx.body = {
user
}
} catch (error) {
ctx.throw(422, error.message)
}
}
/**
* @api {delete} /users/:id Delete a user
* @apiPermission user
* @apiName DeleteUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X DELETE localhost:5000/users/56bd1da600a526986cf65c80
*
* @apiSuccess {StatusCode} 200
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true
* }
*
* @apiUse TokenError
*/
async deleteUser (ctx) {
const user = ctx.body.user
await user.remove()
ctx.status = 200
ctx.body = {
success: true
}
}
// Validate Email Format
async validateEmail (email) {
// eslint-disable-next-line no-useless-escape
if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
return true
}
return false
}
}
module.exports = UserController