+ /**
+ * Routes for users
+ *
+ * @module routes/users
+ * @author Miltos Skondras
+ */
+
+const Router = require('koa-router');
+const bodyParser = require('koa-bodyparser');
+const model = require('../models/users');
+const auth = require('../controllers/auth');
+const {validateUser} = require('../controllers/validation');
+const can = require('../permissions/users');
+
+const prefix = '/api/v1/users';
+const router = Router({prefix: prefix});
+
+
+router.get('/', auth, getAll);
+router.post('/', bodyParser(), validateUser, createUser);
+router.post('/login', auth, login);
+router.get('/:id([0-9]{1,})', auth, getById);
+router.put('/:id([0-9]{1,})', auth, bodyParser(), validateUser, updateUser);
+router.del('/:id([0-9]{1,})', auth, deleteUser);
+
+/**
+ * login
+ *
+ * @description Returns user information
+ * @param {object} ctx - Context object of HTTP Request
+ * @param {function} next - Callback
+ *
+ */
+async function login(ctx, next) {
+ // return any details needed by the client
+ const {ID, username, email, avatarURL} = ctx.state.user
+ const links = {
+ self: `${ctx.protocol}://${ctx.host}${prefix}/${ID}`
+ }
+ ctx.body = {ID, username, email, avatarURL, links};
+}
+
+/**
+ * getAll
+ *
+ * @description Returns all users from the DataBase.
+ * @param {object} ctx - Context object of HTTP Request
+ * @param {function} next - Callback
+ */
+async function getAll(ctx, next) {
+ const permission = can.readAll(ctx.state.user);
+ if (!permission.granted) {
+ ctx.status = 403;
+ } else {
+ const result = await model.getAll();
+ if (result.length) {
+ ctx.body = result;
+ }
+ }
+}
+
+/**
+ * getById
+ *
+ * @decription Returns a user based on the ID
+ * @param {object} ctx - Context object of HTTP Request
+ * @param {function} next - Callback
+ */
+async function getById(ctx, next) {
+ const id = ctx.params.id;
+ const result = await model.getById(id);
+ if (result.length) {
+ const data = result[0]
+ const permission = can.read(ctx.state.user, data);
+ if (!permission.granted) {
+ ctx.status = 403;
+ } else {
+ ctx.body = permission.filter(data);
+ }
+ }
+}
+
+
+/**
+ * createUser
+ *
+ * @description Creates a new user in the Database
+ * @param {object} ctx - Context object of HTTP Request
+ * @param {function} next - Callback
+ */
+async function createUser(ctx, next) {
+ const body = ctx.request.body;
+ const result = await model.add(body);
+ if (result.affectedRows) {
+ const id = result.insertId;
+ ctx.status = 201;
+ ctx.body = {ID: id, created: true, link: `${ctx.request.path}/${id}`};
+ }
+}
+
+/**
+ * updateUser
+ *
+ * @description Updates a user in the Database
+ * @param {object} ctx - Context object of HTTP Request
+ * @param {function} next - Callback
+ */
+async function updateUser(ctx, next) {
+ const id = ctx.params.id;
+ let result = await model.getById(id); // check it exists
+ if (result.length) {
+ let data = result[0];
+ const permission = can.update(ctx.state.user, data);
+ if (!permission.granted) {
+ ctx.status = 403;
+ } else {
+ // exclude fields that should not be updated
+ const newData = permission.filter(ctx.request.body);
+ Object.assign(newData, {ID: id}); // overwrite updatable fields with body data
+ result = await model.update(newData);
+ if (result.affectedRows) {
+ ctx.body = {ID: id, updated: true, link: ctx.request.path};
+ }
+ }
+ }
+}
+
+/**
+ * deleteUser
+ *
+ * @description Deletes a user from the Database
+ * @param {object} ctx - Context object of HTTP Request
+ * @param {function} next - Callback
+ */
+async function deleteUser(ctx) {
+ const id = ctx.params.id;
+ let result = await model.getById(id);
+ if (result.length) {
+ const data = result[0];
+ console.log("trying to delete", data);
+ const permission = can.delete(ctx.state.user, data);
+ if (!permission.granted) {
+ ctx.status = 403;
+ } else {
+ result = await model.delById(id);
+ if (result.affectedRows) {
+ ctx.body = {ID: id, deleted: true}
+ }
+ }
+ }
+}
+
+module.exports = router;
+
+