From b1f2119181ec768dc477ccee87872bf667dfea54 Mon Sep 17 00:00:00 2001 From: Sithira Munasinghe Date: Sat, 16 Jun 2018 08:06:43 +0530 Subject: [PATCH] Second Beta Release. Added JWT for authentication. Added Route Based Authentication. Added DataSeeder Added Auth Functions and Routes ..... and many more bug fixes --- app/Controllers/Http/Auth/LoginController.js | 165 +++---- .../Http/Auth/ProfileController.js | 29 +- app/Controllers/Http/ProjectController.js | 296 ++++++------ app/Controllers/Http/ReleaseController.js | 194 ++++---- app/Controllers/Http/SprintController.js | 292 ++++++------ app/Controllers/Http/TeamController.js | 441 +++++++++--------- app/Controllers/Http/TicketController.js | 234 +++++----- app/Controllers/Http/TicketTypeController.js | 9 - app/Controllers/Http/UserController.js | 323 ++++++------- app/Exceptions/Handler.js | 70 +-- .../Auth/VerificationAuthentication.js | 57 --- app/Middleware/Auth/VerifyAuthentication.js | 86 ++++ app/Middleware/Deletions/ProjectDeleteFail.js | 54 +-- app/Middleware/Deletions/SprintDeleteFail.js | 56 +-- app/Middleware/ProjectFindFail.js | 73 +-- app/Middleware/ReleaseFindFail.js | 49 +- .../SoftDeleted/ProjectFindFailSoftDeleted.js | 119 ++--- .../SoftDeleted/SprintFindFailSoftDeleted.js | 57 +-- .../SoftDeleted/TeamFindFailSoftDeleted.js | 60 +-- .../SoftDeleted/TicketFindFailSoftDeleted.js | 16 +- .../SoftDeleted/UserFindFailSoftDeleted.js | 134 +++--- app/Middleware/SprintFindFail.js | 73 +-- app/Middleware/TeamFindFail.js | 72 +-- app/Middleware/TeamFindFromBody.js | 64 +-- app/Middleware/TicketFindFail.js | 62 ++- app/Middleware/UserFindFail.js | 93 ++-- app/Models/Ticket.js | 62 +-- app/Models/User.js | 5 + app/Validators/TicketCreateUpdate.js | 9 +- config/auth.js | 146 +++--- database/factory.js | 2 +- database/seeds/DataSeeder.js | 50 +- start/app.js | 30 +- start/kernel.js | 69 +-- start/routes.js | 302 ++++++------ 35 files changed, 1998 insertions(+), 1855 deletions(-) delete mode 100644 app/Controllers/Http/TicketTypeController.js delete mode 100644 app/Middleware/Auth/VerificationAuthentication.js create mode 100644 app/Middleware/Auth/VerifyAuthentication.js diff --git a/app/Controllers/Http/Auth/LoginController.js b/app/Controllers/Http/Auth/LoginController.js index a2a48b6..77745eb 100644 --- a/app/Controllers/Http/Auth/LoginController.js +++ b/app/Controllers/Http/Auth/LoginController.js @@ -2,86 +2,91 @@ class LoginController { - - /** - * Login the user. - * - * @param request - * @param response - * @param auth - * @return {Promise<*>} - */ - async login({request, response, auth}) - { - - const { - email, - password - } = request.all(); - - let payLoad = await auth - .withRefreshToken() - .attempt(email, password); - - return response.status(200).json({ - status: "OK", - data: payLoad - }); - - } - - async refreshToken({request, response, auth}) - { - - - - } - - /** - * Logout the currently logged in user. - * - * @param request - * @param response - * @param auth - * @return {Promise<*>} - */ - async logout({request, response, auth}) - { - - try { - - await auth.logout(); - - return response.status(200).json({ - status: "OK", - message: "Successfully Logged out" - }); - - } - catch (error) - { - throw new Error(error); - } - - } - - async check({request, response, auth}) - { - try { - await auth.check(); - - return response.status(403).json({ - status: "OK", - message: "Authenticated" - }) - } catch (error) { - return response.status(403).json({ - status: "ERROR", - message: error - }) - } - } - + + /** + * Login the user. + * + * @param request + * @param response + * @param auth + * @return {Promise<*>} + */ + async login({request, response, auth}) + { + + // get the details from the request body. + const { + email, + password + } = request.all(); + + // exchange an access_token for email and password + let payLoad = await auth + .withRefreshToken() + .attempt(email, password); + + // return the response + return response.status(200).json({ + status: "OK", + data: payLoad + }); + + } + + async refreshToken({request, response, auth}) + { + + + } + + /** + * Logout the currently logged in user. + * + * @param request + * @param response + * @param auth + * @return {Promise<*>} + */ + async logout({request, response, auth}) + { + + try + { + + await auth.logout(); + + return response.status(200).json({ + status: "OK", + message: "Successfully Logged out" + }); + + } + catch (error) + { + throw new Error(error); + } + + } + + async check({request, response, auth}) + { + try + { + await auth.check(); + + return response.status(403).json({ + status: "OK", + message: "Authenticated" + }) + } catch (error) + { + return response.status(403).json({ + status: "ERROR", + message: error + }) + } + } + } module.exports = LoginController; diff --git a/app/Controllers/Http/Auth/ProfileController.js b/app/Controllers/Http/Auth/ProfileController.js index acffa45..536ef29 100644 --- a/app/Controllers/Http/Auth/ProfileController.js +++ b/app/Controllers/Http/Auth/ProfileController.js @@ -1,6 +1,31 @@ -'use strict' +'use strict'; -class ProfileController { +class ProfileController +{ + + async index({request, response, auth}) + { + + try + { + let user = await auth.getUser(); + + return response.status(200).json({ + status: "OK", + authentication: "AUTHENTICATED", + data: user + }) + } + catch (err) + { + return response.status(302).json({ + status: "ERROR", + message: "Please Re-Login" + }) + } + + } + } module.exports = ProfileController; diff --git a/app/Controllers/Http/ProjectController.js b/app/Controllers/Http/ProjectController.js index fbd0709..a000eef 100644 --- a/app/Controllers/Http/ProjectController.js +++ b/app/Controllers/Http/ProjectController.js @@ -4,154 +4,154 @@ const Project = use("App/Models/Project"); class ProjectController { - - /** - * Get all the projects - * - * @param request - * @param response - * @returns {Promise<*|{limit, strict, types}|Promise>} - */ - async index({request, response}) - { - - const projects = await request.post().projects; - - return response.status(200).json({ - status: "OK", - data: projects - }); - - } - - /** - * Get the specified user from the database. - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async show({request, response}) - { - - return response.status(200).json({ - status: "OK", - data: request.post().project - }); - - } - - /** - * Store new project in the database. - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async store({request, response}) - { - - // create the new project in the database. - const project = await Project.create(request.all()); - - // get the team - let team = request.post().team; - - // add the project to the team - team.merge({_project_id: project._id}); - - // save the team - await team.save(); - - // return the response with the newly created data - return response.status(201).json({ - status: "OK", - data: project - }); - - } - - /** - * Update the details of a given resource when a id is provided. - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async update({request, response}) - { - - // get the project from the request body. - const project = request.post().project; - - // update the project instance from the request body - project.merge(request.except(['project'])); - - // save the project - await project.save(); - - // return the response. - return response.status(200).json({ - status: "OK", - data: project - }); - - } - - /** - * Soft delete or hard delete a resource with the given id. - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async destroy({request, response}) - { - - // get the project from the request body. - const project = request.post().project; - - // check if the delete request was a force delete request - let projectId = project._id; - - // get the force delete flags. - const { forceDestroy = "false" } = request.all(); - - if (forceDestroy === "true") - { - - // delete the object form database - await project.delete(); - - // return the response - return response.status(200).json({ - status: "OK", - message: `The project with id: ${projectId} has been force deleted.` - }); - } - else - { - - // set the deleted_at field - const softDelete = { - deleted_at: new Date().toISOString() - }; - - // merge the object - project.merge(softDelete); - - // save the project - await project.save(); - - // return the response to the user. - return response.status(200).json({ - status: "OK", - message: `The project with id: ${projectId} has been deleted.` - }); - } - - } - + + /** + * Get all the projects + * + * @param request + * @param response + * @returns {Promise<*|{limit, strict, types}|Promise>} + */ + async index({request, response}) + { + + const projects = await request.post().projects; + + return response.status(200).json({ + status: "OK", + data: projects + }); + + } + + /** + * Get the specified user from the database. + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async show({request, response}) + { + + return response.status(200).json({ + status: "OK", + data: request.post().project + }); + + } + + /** + * Store new project in the database. + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async store({request, response}) + { + + // create the new project in the database. + const project = await Project.create(request.all()); + + // get the team + let team = request.post().team; + + // add the project to the team + team.merge({_project_id: project._id}); + + // save the team + await team.save(); + + // return the response with the newly created data + return response.status(201).json({ + status: "OK", + data: project + }); + + } + + /** + * Update the details of a given resource when a id is provided. + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async update({request, response}) + { + + // get the project from the request body. + const project = request.post().project; + + // update the project instance from the request body + project.merge(request.except(['project', 'relations'])); + + // save the project + await project.save(); + + // return the response. + return response.status(200).json({ + status: "OK", + data: project + }); + + } + + /** + * Soft delete or hard delete a resource with the given id. + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async destroy({request, response}) + { + + // get the project from the request body. + const project = request.post().project; + + // check if the delete request was a force delete request + let projectId = project._id; + + // get the force delete flags. + const {forceDestroy = "false"} = request.all(); + + if (forceDestroy === "true") + { + + // delete the object form database + await project.delete(); + + // return the response + return response.status(200).json({ + status: "OK", + message: `The project with id: ${projectId} has been force deleted.` + }); + } + else + { + + // set the deleted_at field + const softDelete = { + deleted_at: new Date().toISOString() + }; + + // merge the object + project.merge(softDelete); + + // save the project + await project.save(); + + // return the response to the user. + return response.status(200).json({ + status: "OK", + message: `The project with id: ${projectId} has been deleted.` + }); + } + + } + } module.exports = ProjectController; diff --git a/app/Controllers/Http/ReleaseController.js b/app/Controllers/Http/ReleaseController.js index 064db4d..af064f9 100644 --- a/app/Controllers/Http/ReleaseController.js +++ b/app/Controllers/Http/ReleaseController.js @@ -4,103 +4,103 @@ const Release = use('App/Models/Release'); class ReleaseController { - - async index({ request, response }) - { - - const project = request.post().project; - - const releases = await Release.query() - .where({"_project_id": project._id}) - .fetch(); - - return await response.json({ - status: "OK", - data: releases - }) - - } - - async show({ request, response }) - { - const release = request.post().release; - - return await response.status(200).json({ - status: "OK", - data: release - }); - } - - async store({ request, response }) - { - - let project = request.post().project; - - const release = await Release.create(request.except(['project'])); - - await project.releases().save(release); - - response.status(201).json({ - status: "OK", - data: release - }); - - } - - async update({ request, response }) - { - - const release = request.post().release; - - release.merge(request.except(['project', '_project_id'])); - - await release.save(); - - return await response.json({ - status: "OK", - data: release - }) - - } - - async destory({ request, response }) - { - - const { forceDestroy = "false" } = request.all(); - - const release = request.post().release; - - if (forceDestroy === "true") - { - - await release.delete(); - - return response.json({ - status: "OK", - message: `Release with the release ID: ${releaseId} has been soft deleted.` - }); - - } - else - { - // set the deleted_at field - const softDelete = { - deleted_at: new Date().toISOString() - }; - - release.merge(softDelete); - - await release.save(); - - return response.json({ - status: "OK", - message: `Release with the release ID: ${releaseId} has been soft deleted.` - }); - - } - - } - + + async index({request, response}) + { + + const project = request.post().project; + + const releases = await Release.query() + .where({"_project_id": project._id}) + .fetch(); + + return await response.json({ + status: "OK", + data: releases + }) + + } + + async show({request, response}) + { + const release = request.post().release; + + return await response.status(200).json({ + status: "OK", + data: release + }); + } + + async store({request, response}) + { + + let project = request.post().project; + + const release = await Release.create(request.except(['project', 'relations'])); + + await project.releases().save(release); + + response.status(201).json({ + status: "OK", + data: release + }); + + } + + async update({request, response}) + { + + const release = request.post().release; + + release.merge(request.except(['project', '_project_id'])); + + await release.save(); + + return await response.json({ + status: "OK", + data: release + }) + + } + + async destory({request, response}) + { + + const {forceDestroy = "false"} = request.all(); + + const release = request.post().release; + + if (forceDestroy === "true") + { + + await release.delete(); + + return response.json({ + status: "OK", + message: `Release with the release ID: ${releaseId} has been soft deleted.` + }); + + } + else + { + // set the deleted_at field + const softDelete = { + deleted_at: new Date().toISOString() + }; + + release.merge(softDelete); + + await release.save(); + + return response.json({ + status: "OK", + message: `Release with the release ID: ${releaseId} has been soft deleted.` + }); + + } + + } + } module.exports = ReleaseController; diff --git a/app/Controllers/Http/SprintController.js b/app/Controllers/Http/SprintController.js index 14cf21a..9b18329 100644 --- a/app/Controllers/Http/SprintController.js +++ b/app/Controllers/Http/SprintController.js @@ -3,151 +3,153 @@ const Sprint = use('App/Models/Sprint'); const Project = use('App/Models/Project'); -class SprintController { - - /** - * Get all the sprints for a specific project - * - * @param params - * @param response - * @return {Promise<{limit, strict, types}|any>} - */ - async index({request, response}) { - - // get the sprint from the request body. - const project = request.post().project; - - // get all the sprints that belongs to a project. - const sprints = await Sprint.query() - .where({"_project_id": project._id}) - .fetch(); - - // return the response. - return await response.status(200).json({ - status: "OK", - data: sprints - }); - - } - - /** - * Get a sprint that belongs to a project - * - * @param request - * @param response - * @return {Promise<{limit, strict, types}|any>} - */ - async show({request, response}) - { - const sprint = request.post().sprint; - - return await response.status(200).json({ - status: "OK", - data: sprint - }) - } - - /** - * Store a Sprint in a database. - * - * @param request - * @param response - * @return {Promise<{limit, strict, types}|any>} - */ - async store({request, response}) - { - - let project = request.post().project; - - let sprint = await Sprint.create(request.except(['project'])); - - await project.sprints().save(sprint); - - return await response.status(201).json({ - status: "OK", - data: sprint - }) - - } - - /** - * Update an given sprint. - * - * @param request - * @param response - * @return {Promise<{limit, strict, types}|any>} - */ - async update({request, response}) - { - - // get the sprint from the request body, added by the middleware. - let sprint = request.post().sprint; - - // swap the current details with the updated details - sprint.merge(request.except(['sprint', '_project_id'])); - - // wait for the sprint to save. - await sprint.save(); - - // send the response. - return await response.status(200).json({ - status: "OK", - data: sprint - }); - - } - - /** - * Soft delete or force delete the given sprint. - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async destroy({request, response}) - { - - // get the sprint from the request body - let sprint = request.post().sprint; - - // get the sprintId - const sprintId = sprint._id; - - // get the forceDestroy params - const { forceDestroy = "false" } = request.all(); - - // check for the demanded deletion type. - if (forceDestroy === "true") - { - await sprint.delete(); - - return response.status(200).json({ - status: "OK", - message: `The Sprint with id: ${sprintId} is force deleted.` - }); - } - else - { - // set the deleted_at field - const softDelete = { - deleted_at: new Date().toISOString() - }; - - // set the new attributes - sprint.merge(softDelete); - - // save the updates in the database. - await sprint.save(); - - // return the response to the user. - return response.status(200).json({ - status: "OK", - message: `The Sprint with id: ${sprintId} has been deleted.` - }) - } - - } - +class SprintController +{ + + /** + * Get all the sprints for a specific project + * + * @param params + * @param response + * @return {Promise<{limit, strict, types}|any>} + */ + async index({request, response}) + { + + // get the sprint from the request body. + const project = request.post().project; + + // get all the sprints that belongs to a project. + const sprints = await Sprint.query() + .where({"_project_id": project._id}) + .fetch(); + + // return the response. + return await response.status(200).json({ + status: "OK", + data: sprints + }); + + } + + /** + * Get a sprint that belongs to a project + * + * @param request + * @param response + * @return {Promise<{limit, strict, types}|any>} + */ + async show({request, response}) + { + const sprint = request.post().sprint; + + return await response.status(200).json({ + status: "OK", + data: sprint + }) + } + + /** + * Store a Sprint in a database. + * + * @param request + * @param response + * @return {Promise<{limit, strict, types}|any>} + */ + async store({request, response}) + { + + let project = request.post().project; + + let sprint = await Sprint.create(request.except(['project'])); + + await project.sprints().save(sprint); + + return await response.status(201).json({ + status: "OK", + data: sprint + }) + + } + + /** + * Update an given sprint. + * + * @param request + * @param response + * @return {Promise<{limit, strict, types}|any>} + */ + async update({request, response}) + { + + // get the sprint from the request body, added by the middleware. + let sprint = request.post().sprint; + + // swap the current details with the updated details + sprint.merge(request.except(['sprint', '_project_id', 'relations'])); + + // wait for the sprint to save. + await sprint.save(); + + // send the response. + return await response.status(200).json({ + status: "OK", + data: sprint + }); + + } + + /** + * Soft delete or force delete the given sprint. + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async destroy({request, response}) + { + + // get the sprint from the request body + let sprint = request.post().sprint; + + // get the sprintId + const sprintId = sprint._id; + + // get the forceDestroy params + const {forceDestroy = "false"} = request.all(); + + // check for the demanded deletion type. + if (forceDestroy === "true") + { + await sprint.delete(); + + return response.status(200).json({ + status: "OK", + message: `The Sprint with id: ${sprintId} is force deleted.` + }); + } + else + { + // set the deleted_at field + const softDelete = { + deleted_at: new Date().toISOString() + }; + + // set the new attributes + sprint.merge(softDelete); + + // save the updates in the database. + await sprint.save(); + + // return the response to the user. + return response.status(200).json({ + status: "OK", + message: `The Sprint with id: ${sprintId} has been deleted.` + }) + } + + } + } module.exports = SprintController; diff --git a/app/Controllers/Http/TeamController.js b/app/Controllers/Http/TeamController.js index 64c6b97..dea12f6 100644 --- a/app/Controllers/Http/TeamController.js +++ b/app/Controllers/Http/TeamController.js @@ -4,226 +4,227 @@ const Team = use("App/Models/Team"); const User = use("App/Models/User"); -class TeamController { - - // Todo: Only Admins can access this - - /** - * Get all the teams that are in the system. - * - * @param response - * @returns {Promise<*|{limit, strict, types}|Promise>} - */ - async index({response}) - { - return response.status(200).json({ - status: "OK", - data: await Team.all() - }); - } - - /** - * Create a new team in the system. - * - * @param request - * @param response - * @returns {Promise<*|{limit, strict, types}|Promise>} - */ - async store({request, response}) - { - // create the new team - let team = await Team.create(request.all()); - - // send the response to client. - return response.status(201).json({ - status: "OK", - data: team - }); - } - - /** - * Get a specific team object. - * - * @param response - * @param request - * @returns {Promise<*|{limit, strict, types}|Promise>} - */ - async show({request, response}) - { - - // get the team from the request body. - const team = request.post().team; - - // return the team object - return response.status(200).json({ - status: "OK", - data: team - }); - - } - - /** - * Update a team - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async update({request, response}) - { - - const team = request.post().team; - - team.merge(request.except(['team'])); - - await team.save(); - - return response.status(200).json({ - status: "OK", - data: team - }); - - } - - /** - * soft delete or force delete a team. - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async destroy({request, response}) - { - - const team = request.post().team; - - const teamId = team._id; - - const { forceDestroy = "false" } = request.all(); - - if (forceDestroy === "true") - { - - // delete the object from the database. - await team.delete(); - - // return the response. - return response.status(200).json({ - status: "OK", - messages: `The team with the id: ${teamId} has been force deleted.` - }) - - } - else - { - // set the deleted_at field - const softDelete = { - deleted_at: new Date().toISOString() - }; - - team.merge(softDelete); - - await team.save(); - - return response.status(200).json({ - status: "OK", - message: `The team with the id: ${teamId} has been successfully soft deleted` - }) - } - - } - - /** - * Add a user to an existing team - * - * @param request - * @param params - * @return {Promise<*>} - */ - async addMember({request, response}) - { - - // get the teamId from the request body - let teamId = request.post().team._id; - - // get the team with users in it - let team = await Team.with(['users']).find(teamId); - - console.log(team); - - // count the number of team members - let teamUserCount = team.$relations.users.rows.length; - - // limit the number of heads per team - if (teamUserCount <= 5) - { - - // get the user the request body - let user = request.post().user; - - if (!user.hasOwnProperty("type") && !(user.type === "admin" || user.type === "manager")) - { - // add the user to the team instance (many-to-many) - user.merge({_team_id: team._id, type: "user"}); - } - - await user.save(); - - // return the response - return response.status(200).json({ - status: "OK", - data: { - team: team, - user: user - } - }); - - } - - // return the error message - return response.status(400).json({ - status: "ERROR", - message: `Maximum user count for team ${team.name} of ${teamUserCount} / 05 has reached` - }); - - } - - /** - * Remove a user from the team. - * - * @param request - * @param response - * @return {Promise<*>} - */ - async removeMember({request, response}) - { - - // find the team with users - let team = await Team.with(['users']).find(request.post().team._id); - - let user = request.post().user; - - if (!user.hasOwnProperty("type") && !(user.type === "admin" || user.type === "manager")) - { - // add the user to the team instance (many-to-many) - user.merge({type: "client"}); - } - - // detach the user from the team - user._team_id = null; - - // save the user. - await user.save(); - - // return the response - return response.status(200).json({ - status: "OK", - data: { - team: team - } - }) - - } +class TeamController +{ + + // Todo: Only Admins can access this + + /** + * Get all the teams that are in the system. + * + * @param response + * @returns {Promise<*|{limit, strict, types}|Promise>} + */ + async index({response}) + { + return response.status(200).json({ + status: "OK", + data: await Team.all() + }); + } + + /** + * Create a new team in the system. + * + * @param request + * @param response + * @returns {Promise<*|{limit, strict, types}|Promise>} + */ + async store({request, response}) + { + // create the new team + let team = await Team.create(request.all()); + + // send the response to client. + return response.status(201).json({ + status: "OK", + data: team + }); + } + + /** + * Get a specific team object. + * + * @param response + * @param request + * @returns {Promise<*|{limit, strict, types}|Promise>} + */ + async show({request, response}) + { + + // get the team from the request body. + const team = request.post().team; + + // return the team object + return response.status(200).json({ + status: "OK", + data: team + }); + + } + + /** + * Update a team + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async update({request, response}) + { + + const team = request.post().team; + + team.merge(request.except(['team', 'relations'])); + + await team.save(); + + return response.status(200).json({ + status: "OK", + data: team + }); + + } + + /** + * soft delete or force delete a team. + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async destroy({request, response}) + { + + const team = request.post().team; + + const teamId = team._id; + + const {forceDestroy = "false"} = request.all(); + + if (forceDestroy === "true") + { + + // delete the object from the database. + await team.delete(); + + // return the response. + return response.status(200).json({ + status: "OK", + messages: `The team with the id: ${teamId} has been force deleted.` + }) + + } + else + { + // set the deleted_at field + const softDelete = { + deleted_at: new Date().toISOString() + }; + + team.merge(softDelete); + + await team.save(); + + return response.status(200).json({ + status: "OK", + message: `The team with the id: ${teamId} has been successfully soft deleted` + }) + } + + } + + /** + * Add a user to an existing team + * + * @param request + * @param params + * @return {Promise<*>} + */ + async addMember({request, response}) + { + + // get the teamId from the request body + let teamId = request.post().team._id; + + // get the team with users in it + let team = await Team.with(['users']).find(teamId); + + console.log(team); + + // count the number of team members + let teamUserCount = team.$relations.users.rows.length; + + // limit the number of heads per team + if (teamUserCount <= 5) + { + + // get the user the request body + let user = request.post().user; + + if (!user.hasOwnProperty("type") && !(user.type === "admin" || user.type === "manager")) + { + // add the user to the team instance (many-to-many) + user.merge({_team_id: team._id, type: "user"}); + } + + await user.save(); + + // return the response + return response.status(200).json({ + status: "OK", + data: { + team: team, + user: user + } + }); + + } + + // return the error message + return response.status(400).json({ + status: "ERROR", + message: `Maximum user count for team ${team.name} of ${teamUserCount} / 05 has reached` + }); + + } + + /** + * Remove a user from the team. + * + * @param request + * @param response + * @return {Promise<*>} + */ + async removeMember({request, response}) + { + + // find the team with users + let team = await Team.with(['users']).find(request.post().team._id); + + let user = request.post().user; + + if (!user.hasOwnProperty("type") && !(user.type === "admin" || user.type === "manager")) + { + // add the user to the team instance (many-to-many) + user.merge({type: "client"}); + } + + // detach the user from the team + user._team_id = null; + + // save the user. + await user.save(); + + // return the response + return response.status(200).json({ + status: "OK", + data: { + team: team + } + }) + + } } module.exports = TeamController; diff --git a/app/Controllers/Http/TicketController.js b/app/Controllers/Http/TicketController.js index 70be00a..235e262 100644 --- a/app/Controllers/Http/TicketController.js +++ b/app/Controllers/Http/TicketController.js @@ -4,123 +4,123 @@ const Ticket = use('App/Models/Ticket'); class TicketController { - - /** - * Get all tickets that belongs to a project -> sprint - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async index({request, response}) - { - - // get the sprint because ticket belongs to a sprint - const sprint = request.post().sprint; - - // get all tickets from the database. - const tickets = await Ticket.query() - .where('_sprint_id', sprint._id) - .fetch(); - - // return the details - return response.status(200).json({ - status: "OK", - data: tickets - }) - - } - - /** - * Get the ticket and show it - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async show({request, response}) - { - - const ticket = request.post().ticket; - - return response.status(200).json({ - status: "OK", - data: ticket - }) - - } - - async store({request, response}) - { - - const sprint = request.post().sprint; - - const ticket = await Ticket.create(request.except(['project', 'sprint'])); - - await sprint.tickets().save(ticket); - - return response.status(201).json({ - status: "OK", - data: ticket - }) - - } - - async update({request, response}) - { - - let ticket = request.post().ticket; - - ticket.merge(request.except(['project', 'sprint'])); - - await ticket.save(); - - return response.status(200).json({ - status: "OK", - data: ticket - }) - - } - - async destroy({request, response}) - { - - const ticket = request.post().ticket; - - let ticketId = ticket._id; - - const { forceDestroy = "false"} = request.all(); - - if (forceDestroy === "true") - { - await ticket.delete(); - - return response.status(200).json({ - status: "OK", - message: `The ticket with the id: ${ticketId} has been force deleted` - }); - } - else - { - - // set the deleted_at field - const softDelete = { - deleted_at: new Date().toISOString() - }; - - ticket.merge(softDelete); - - await ticket.save(); - - return response.status(200).json({ - status: "OK", - message: `The ticket with the id: ${ticketId} has been successfully soft deleted` - }) - - } - - } - + + /** + * Get all tickets that belongs to a project -> sprint + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async index({request, response}) + { + + // get the sprint because ticket belongs to a sprint + const sprint = request.post().sprint; + + // get all tickets from the database. + const tickets = await Ticket.query() + .where('_sprint_id', sprint._id) + .fetch(); + + // return the details + return response.status(200).json({ + status: "OK", + data: tickets + }) + + } + + /** + * Get the ticket and show it + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async show({request, response}) + { + + const ticket = request.post().ticket; + + return response.status(200).json({ + status: "OK", + data: ticket + }) + + } + + async store({request, response}) + { + + const sprint = request.post().sprint; + + const ticket = await Ticket.create(request.except(['project', 'sprint'])); + + await sprint.tickets().save(ticket); + + return response.status(201).json({ + status: "OK", + data: ticket + }) + + } + + async update({request, response}) + { + + let ticket = request.post().ticket; + + ticket.merge(request.except(['project', 'sprint', 'relations'])); + + await ticket.save(); + + return response.status(200).json({ + status: "OK", + data: ticket + }) + + } + + async destroy({request, response}) + { + + const ticket = request.post().ticket; + + let ticketId = ticket._id; + + const {forceDestroy = "false"} = request.all(); + + if (forceDestroy === "true") + { + await ticket.delete(); + + return response.status(200).json({ + status: "OK", + message: `The ticket with the id: ${ticketId} has been force deleted` + }); + } + else + { + + // set the deleted_at field + const softDelete = { + deleted_at: new Date().toISOString() + }; + + ticket.merge(softDelete); + + await ticket.save(); + + return response.status(200).json({ + status: "OK", + message: `The ticket with the id: ${ticketId} has been successfully soft deleted` + }) + + } + + } + } module.exports = TicketController; diff --git a/app/Controllers/Http/TicketTypeController.js b/app/Controllers/Http/TicketTypeController.js deleted file mode 100644 index 475bebf..0000000 --- a/app/Controllers/Http/TicketTypeController.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -class TicketTypeController -{ - - -} - -module.exports = TicketTypeController; diff --git a/app/Controllers/Http/UserController.js b/app/Controllers/Http/UserController.js index 808a81b..bbcd09e 100644 --- a/app/Controllers/Http/UserController.js +++ b/app/Controllers/Http/UserController.js @@ -4,167 +4,168 @@ const Database = use("Database"); const User = use("App/Models/User"); -class UserController { - - /** - * Get all the users in the system - * - * @param request - * @param response - * @returns {Promise} - */ - async index({request, response}) - { - - let users = request.post().users; - - // return the response - response.status(200).json({ - result: "OK", - data: users - }) - } - - /** - * Get a single user object - * - * @param request - * @param response - * @return {Promise<*|{limit, strict, types}|Promise>} - */ - async show({request, response}) - { - return response.json({ - status: "OK", - data: request.post().user - }); - } - - /** - * Store a new user in the database. - * - * @param request - * @param response - * @returns {Promise<*|{limit, strict, types}|Promise>} - */ - async store({request, response}) - { - - // // define the validation rules for incoming request - // const rules = { - // name: 'required|min:3', - // email: 'required|email', - // password: 'required|min:8' - // }; - // - // // validate the request - // const validator = await validateAll(request.all(), rules); - // - // // check for validation errors - // if (validator.fails()) - // { - // return response.status(400).json({ - // result: "ERROR", - // data: validator.messages() - // }) - // } - - // create the new user - const user = await User.create(request.all()); - - // return the newly created user object - return response.status(201).json({ - status: "OK", - data: user - }); - - } - - /** - * Update user details. Return the user object on success. - * - * @param request - * @param response - * @returns {Promise<*|{limit, strict, types}|Promise>} - */ - async update({request, response}) - { - - // get the user from the request body. - let user = request.post().user; - - // merge everything togather - user.merge(request.except(["user"])); - - // save the changes in the database. - await user.save(); - - // return the success response to the user. - return response.json({ - status: "OK", - data: user - }); - - } - - /** - * Delete a specif row from the database - * - * @param request - * @param response - * @param params - * @returns {Promise<*|{limit, strict, types}|Promise>} - */ - async destroy({request, response}) - { - - // get the force delete parameter. - const { - forceDestroy = "false", - } = request.all(); - - // get the user form the database - let user = request.post().user; - - let userId = user._id; - - // check if the request is for a soft delete or hard delete - if (forceDestroy === "false") - { - - // define the deleted_at - let deleteFields = { - deleted_at: new Date().toISOString() - }; - - // add delete params - user.merge(deleteFields); - - // save the obj3ct in database - await user.save(); - - // return the correct response. - return response.status(200).json({ - status: "OK", - data: `The user with the id: ${userId} has been successfully deleted` - }); - - } - else - { - - // delete forever - await user.delete(); - - // return the response - return response.status(200).json({ - status: "OK", - message: `User with the id: ${userId} has been successfully deleted.` - }); - } - - - } +class UserController +{ + + /** + * Get all the users in the system + * + * @param request + * @param response + * @returns {Promise} + */ + async index({request, response}) + { + + let users = request.post().users; + + // return the response + response.status(200).json({ + result: "OK", + data: users + }) + } + + /** + * Get a single user object + * + * @param request + * @param response + * @return {Promise<*|{limit, strict, types}|Promise>} + */ + async show({request, response}) + { + return response.json({ + status: "OK", + data: request.post().user + }); + } + + /** + * Store a new user in the database. + * + * @param request + * @param response + * @returns {Promise<*|{limit, strict, types}|Promise>} + */ + async store({request, response}) + { + + // // define the validation rules for incoming request + // const rules = { + // name: 'required|min:3', + // email: 'required|email', + // password: 'required|min:8' + // }; + // + // // validate the request + // const validator = await validateAll(request.all(), rules); + // + // // check for validation errors + // if (validator.fails()) + // { + // return response.status(400).json({ + // result: "ERROR", + // data: validator.messages() + // }) + // } + + // create the new user + const user = await User.create(request.all()); + + // return the newly created user object + return response.status(201).json({ + status: "OK", + data: user + }); + + } + + /** + * Update user details. Return the user object on success. + * + * @param request + * @param response + * @returns {Promise<*|{limit, strict, types}|Promise>} + */ + async update({request, response}) + { + + // get the user from the request body. + let user = request.post().user; + + // merge everything togather + user.merge(request.except(["user", 'relations'])); + + // save the changes in the database. + await user.save(); + + // return the success response to the user. + return response.json({ + status: "OK", + data: user + }); + + } + + /** + * Delete a specif row from the database + * + * @param request + * @param response + * @param params + * @returns {Promise<*|{limit, strict, types}|Promise>} + */ + async destroy({request, response}) + { + + // get the force delete parameter. + const { + forceDestroy = "false", + } = request.all(); + + // get the user form the database + let user = request.post().user; + + let userId = user._id; + + // check if the request is for a soft delete or hard delete + if (forceDestroy === "false") + { + + // define the deleted_at + let deleteFields = { + deleted_at: new Date().toISOString() + }; + + // add delete params + user.merge(deleteFields); + + // save the obj3ct in database + await user.save(); + + // return the correct response. + return response.status(200).json({ + status: "OK", + data: `The user with the id: ${userId} has been successfully deleted` + }); + + } + else + { + + // delete forever + await user.delete(); + + // return the response + return response.status(200).json({ + status: "OK", + message: `User with the id: ${userId} has been successfully deleted.` + }); + } + + + } } module.exports = UserController; diff --git a/app/Exceptions/Handler.js b/app/Exceptions/Handler.js index 0635f24..47642ff 100644 --- a/app/Exceptions/Handler.js +++ b/app/Exceptions/Handler.js @@ -8,37 +8,43 @@ const BaseExceptionHandler = use('BaseExceptionHandler'); * * @class ExceptionHandler */ -class ExceptionHandler extends BaseExceptionHandler { - /** - * Handle exception thrown during the HTTP lifecycle - * - * @method handle - * - * @param {Object} error - * @param {Object} options.request - * @param {Object} options.response - * - * @return {void} - */ - async handle (error, { request, response }) { - - console.log(error); - - response.status(error.status).json({status: "ERROR", message: error.message}) - } - - /** - * Report exception for logging or debugging. - * - * @method report - * - * @param {Object} error - * @param {Object} options.request - * - * @return {void} - */ - async report (error, { request }) { - } +class ExceptionHandler extends BaseExceptionHandler +{ + /** + * Handle exception thrown during the HTTP lifecycle + * + * @method handle + * + * @param {Object} error + * @param request + * @param response + * + * @return {void} + */ + async handle(error, {request, response}) + { + + console.log(error); + + return response.status(error.status).json({ + status: "ERROR", + message: error.message + }) + } + + /** + * Report exception for logging or debugging. + * + * @method report + * + * @param {Object} error + * @param {Object} options.request + * + * @return {void} + */ + async report(error, {request}) + { + } } -module.exports = ExceptionHandler +module.exports = ExceptionHandler; diff --git a/app/Middleware/Auth/VerificationAuthentication.js b/app/Middleware/Auth/VerificationAuthentication.js deleted file mode 100644 index 63b93f0..0000000 --- a/app/Middleware/Auth/VerificationAuthentication.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict' - -class VerificationAuthentication -{ - - async handle ({ request, response, auth}, next, schemes) - { - - let user; - - try - { - - // get the user by authenticating the user with the JWT token - user = await auth.getUser(); - - // if we have a prop for admin - if (schemes.indexOf("admin") !== -1) - { - if (user.type !== "admin") - { - return response.status(403).json({ - status: "ERROR", - type: "admin", - message: "You don't have required permissions" - }); - } - } - - // if we have prop for a manager - if (schemes.indexOf("manager") !== -1) - { - if (user.type !== "manager") - { - return response.status(403).json({ - status: "ERROR", - type: "manager", - message: "You don't have required permissions" - }); - } - } - - // return for the next action. - await next(); - } - catch (error) - { - return response.status(403).json({ - status: "ERROR", - message: "Missing, Invalid or expired token. Please Re-Login" - }) - } - - } -} - -module.exports = VerificationAuthentication; diff --git a/app/Middleware/Auth/VerifyAuthentication.js b/app/Middleware/Auth/VerifyAuthentication.js new file mode 100644 index 0000000..7dde32c --- /dev/null +++ b/app/Middleware/Auth/VerifyAuthentication.js @@ -0,0 +1,86 @@ +'use strict'; + +class VerifyAuthentication +{ + + async handle({request, response, auth}, next, props) + { + + try + { + + // get the user by authenticating the user with the JWT token + let user = await auth.getUser(); + + // if the user isn't an admin, check for the rest + if (user.type !== "admin") + { + // if we have a prop for admin + if (props.indexOf("admin") !== -1) + { + + if (user.type !== "admin") + { + return response.status(403).json({ + status: "ERROR", + type: "admin", + message: "You don't have required permissions" + }); + } + } + + // if we have prop for a manager + if (props.indexOf("manager") !== -1) + { + if (user.type !== "manager") + { + return response.status(403).json({ + status: "ERROR", + type: "manager", + message: "You don't have required permissions" + }); + } + } + + // if we have prop for a manager + if (props.indexOf("developer") !== -1) + { + if (user.type !== "developer") + { + return response.status(403).json({ + status: "ERROR", + type: "developer", + message: "You don't have required permissions" + }); + } + } + + // if we have prop for a client + if (props.indexOf("client") !== -1) + { + if (user.type !== "client") + { + return response.status(403).json({ + status: "ERROR", + type: "client", + message: "You don't have required permissions" + }); + } + } + } + + // return for the next action. + await next(); + } + catch (error) + { + return response.status(403).json({ + status: "ERROR", + message: "Missing, Invalid or expired token. Please Re-Login" + }); + } + + } +} + +module.exports = VerifyAuthentication; diff --git a/app/Middleware/Deletions/ProjectDeleteFail.js b/app/Middleware/Deletions/ProjectDeleteFail.js index c974893..c919d9e 100644 --- a/app/Middleware/Deletions/ProjectDeleteFail.js +++ b/app/Middleware/Deletions/ProjectDeleteFail.js @@ -4,33 +4,33 @@ const Project = use('App/Models/Project'); class ProjectDeleteFail { - async handle({ request, response, params }, next) - { - const { - forceDestroy = "false" - } = request.all(); - - let projectId = request.post().project._id; - - let sprints = await Project.with(['sprints']).find(projectId); - - if (forceDestroy === "false") - { - - let sprintsCount = await sprints.sprints().count(); - - if (sprintsCount >= 1) - { - return response.status(400).json({ - status: "ERROR", - message: `You have active ${sprintsCount} sprints on the projects.` - }) - } - } - - // call next to advance the request - await next() - } + async handle({request, response, params}, next) + { + const { + forceDestroy = "false" + } = request.all(); + + let projectId = request.post().project._id; + + let sprints = await Project.with(['sprints']).find(projectId); + + if (forceDestroy === "false") + { + + let sprintsCount = await sprints.sprints().count(); + + if (sprintsCount >= 1) + { + return response.status(400).json({ + status: "ERROR", + message: `You have active ${sprintsCount} sprints on the projects.` + }) + } + } + + // call next to advance the request + await next() + } } module.exports = ProjectDeleteFail; diff --git a/app/Middleware/Deletions/SprintDeleteFail.js b/app/Middleware/Deletions/SprintDeleteFail.js index 5ed1d5e..c42f5bc 100644 --- a/app/Middleware/Deletions/SprintDeleteFail.js +++ b/app/Middleware/Deletions/SprintDeleteFail.js @@ -4,34 +4,34 @@ const Sprint = use('App/Models/Sprint'); class SprintDeleteFail { - - async handle({request, response, params}, next) - { - - const { - forceDestroy = "false" - } = request.all(); - - let sprintId = request.post().sprint._id; - - let tickets = await Sprint.with(['tickets']).find(sprintId); - - if (forceDestroy === "false") - { - const ticketCount = await tickets.tickets().count(); - - if (ticketCount >= 1) - { - return response.status(400).json({ - status: "ERROR", - message: `You have active ${ticketCount} tickets on the sprints` - }) - } - } - - // call next to advance the request - await next() - } + + async handle({request, response, params}, next) + { + + const { + forceDestroy = "false" + } = request.all(); + + let sprintId = request.post().sprint._id; + + let tickets = await Sprint.with(['tickets']).find(sprintId); + + if (forceDestroy === "false") + { + const ticketCount = await tickets.tickets().count(); + + if (ticketCount >= 1) + { + return response.status(400).json({ + status: "ERROR", + message: `You have active ${ticketCount} tickets on the sprints` + }) + } + } + + // call next to advance the request + await next() + } } module.exports = SprintDeleteFail; diff --git a/app/Middleware/ProjectFindFail.js b/app/Middleware/ProjectFindFail.js index d73bc73..1e86ce8 100644 --- a/app/Middleware/ProjectFindFail.js +++ b/app/Middleware/ProjectFindFail.js @@ -2,41 +2,44 @@ const Project = use("App/Models/Project"); -class ProjectFindFail { - - async handle({request, response, params}, next) { - - const { - forceDestroy = "false", - relations = "false", - } = request.all(); - - let project = null; - - if (relations === "true") - { - project = await Project.with(['client', 'team']).find(params.projectId); - } - else - { - project = await Project.find(params.projectId) - } - - // check for the project existence - if (project === null || project === undefined || (forceDestroy === "false" && project.$attributes.hasOwnProperty("deleted_at"))) { - // return the error response. - return response.status(400).json({ - status: "ERROR", - message: `Project with the id: ${params.projectId} could not be found !` - }); - } - - // attach the project object to the body. - request.body.project = project; - - // call next to advance the request - await next() - } +class ProjectFindFail +{ + + async handle({request, response, params}, next) + { + + const { + forceDestroy = "false", + relations = "false", + } = request.all(); + + let project = null; + + if (relations === "true") + { + project = await Project.with(['client', 'team']).find(params.projectId); + } + else + { + project = await Project.find(params.projectId) + } + + // check for the project existence + if (project === null || project === undefined || (forceDestroy === "false" && project.$attributes.hasOwnProperty("deleted_at"))) + { + // return the error response. + return response.status(400).json({ + status: "ERROR", + message: `Project with the id: ${params.projectId} could not be found !` + }); + } + + // attach the project object to the body. + request.body.project = project; + + // call next to advance the request + await next() + } } module.exports = ProjectFindFail; diff --git a/app/Middleware/ReleaseFindFail.js b/app/Middleware/ReleaseFindFail.js index 1204b1c..1142960 100644 --- a/app/Middleware/ReleaseFindFail.js +++ b/app/Middleware/ReleaseFindFail.js @@ -4,30 +4,31 @@ const Release = use('App/Models/Release'); class ReleaseFindFail { - - async handle ({ request, response, params }, next) { - - // try to find the user from the database - let release = await Release.find(params.releaseId); - - // check for the users - if (release === null) - { - - // return 400 response with the message, if the user does not exists. - return response.status(400).json({ - status: "ERROR", - message: `Release with the id of ${params.releaseId} could not be found.` - }); - } - - // add the user object to the request body. - request.body.release = release; - - // carry on with the request. - await next() - - } + + async handle({request, response, params}, next) + { + + // try to find the user from the database + let release = await Release.find(params.releaseId); + + // check for the users + if (release === null) + { + + // return 400 response with the message, if the user does not exists. + return response.status(400).json({ + status: "ERROR", + message: `Release with the id of ${params.releaseId} could not be found.` + }); + } + + // add the user object to the request body. + request.body.release = release; + + // carry on with the request. + await next() + + } } module.exports = ReleaseFindFail; diff --git a/app/Middleware/SoftDeleted/ProjectFindFailSoftDeleted.js b/app/Middleware/SoftDeleted/ProjectFindFailSoftDeleted.js index 41e0a69..80368c7 100644 --- a/app/Middleware/SoftDeleted/ProjectFindFailSoftDeleted.js +++ b/app/Middleware/SoftDeleted/ProjectFindFailSoftDeleted.js @@ -4,65 +4,66 @@ const Project = use('App/Models/Project'); class ProjectFindFailSoftDeleted { - - async handle ({ request, response, params }, next) { - - let projects = null; - - let { - pluck = "false", - showAll = "false", - plucks - } = request.all(); - - if (pluck === "true") - { - - if (plucks === undefined || plucks == null) - { - - projects = await Project.query().setVisible(['_id', 'name']).fetch(); - - } - else - { - - plucks = JSON.parse(plucks); - - if (plucks.length >= 1) - { - projects = await Project.query().setVisible(plucks).fetch(); - } - else - { - projects = await Project.query().setVisible(['_id', 'name']).fetch(); - } - - } - - } - else - { - projects = await Project.all(); - } - - if (showAll === "false") - { - for (let i = 0; i < projects.rows.length; i++) - { - if (projects.rows[i].$attributes.hasOwnProperty("deleted_at")) - { - - projects.rows.splice(i, 1); - - } - } - } - - request.body.projects = projects; - - await next() - } + + async handle({request, response, params}, next) + { + + let projects = null; + + let { + pluck = "false", + showAll = "false", + plucks + } = request.all(); + + if (pluck === "true") + { + + if (plucks === undefined || plucks == null) + { + + projects = await Project.query().setVisible(['_id', 'name']).fetch(); + + } + else + { + + plucks = JSON.parse(plucks); + + if (plucks.length >= 1) + { + projects = await Project.query().setVisible(plucks).fetch(); + } + else + { + projects = await Project.query().setVisible(['_id', 'name']).fetch(); + } + + } + + } + else + { + projects = await Project.all(); + } + + if (showAll === "false") + { + for (let i = 0; i < projects.rows.length; i++) + { + if (projects.rows[i].$attributes.hasOwnProperty("deleted_at")) + { + + projects.rows.splice(i, 1); + + } + } + } + + request.body.projects = projects; + + await next() + } } module.exports = ProjectFindFailSoftDeleted; diff --git a/app/Middleware/SoftDeleted/SprintFindFailSoftDeleted.js b/app/Middleware/SoftDeleted/SprintFindFailSoftDeleted.js index 96a0807..c1724f7 100644 --- a/app/Middleware/SoftDeleted/SprintFindFailSoftDeleted.js +++ b/app/Middleware/SoftDeleted/SprintFindFailSoftDeleted.js @@ -2,34 +2,35 @@ const Sprint = use('App/Models/Sprint'); -class SprintFindFailSoftDeleted { - - async handle({request, response, params}, next) - { - - const { - showAll = "false" - } = request.all(); - - let sprints = await Sprint.all(); - - if (showAll === "false") - { - for (let i = 0; i < sprints.rows.length; i++) - { - - if (sprints[i].$attributes.hasOwnProperty("deleted_at")) - { - sprints.rows.splice(i, 1); - } - } - } - - request.body.sprints = sprints; - - // call next to advance the request - await next() - } +class SprintFindFailSoftDeleted +{ + + async handle({request, response, params}, next) + { + + const { + showAll = "false" + } = request.all(); + + let sprints = await Sprint.all(); + + if (showAll === "false") + { + for (let i = 0; i < sprints.rows.length; i++) + { + + if (sprints[i].$attributes.hasOwnProperty("deleted_at")) + { + sprints.rows.splice(i, 1); + } + } + } + + request.body.sprints = sprints; + + // call next to advance the request + await next() + } } module.exports = SprintFindFailSoftDeleted; diff --git a/app/Middleware/SoftDeleted/TeamFindFailSoftDeleted.js b/app/Middleware/SoftDeleted/TeamFindFailSoftDeleted.js index 6e297be..98bfa56 100644 --- a/app/Middleware/SoftDeleted/TeamFindFailSoftDeleted.js +++ b/app/Middleware/SoftDeleted/TeamFindFailSoftDeleted.js @@ -2,35 +2,37 @@ const Team = use('App/Models/Team'); -class TeamFindFailSoftDeleted { - - async handle({request, response, params}, next) { - - const { - showAll = "false" - } = request.all(); - - let teams = await Team.all(); - - if (showAll === "false") - { - for (let i = 0; i < teams.rows.length; i++) - { - - if (teams.rows[i].$attributes.hasOwnProperty("deleted_at")) - { - - teams.rows.splice(i, 1); - - } - } - } - - request.body.teams = teams; - - // call next to advance the request - await next() - } +class TeamFindFailSoftDeleted +{ + + async handle({request, response, params}, next) + { + + const { + showAll = "false" + } = request.all(); + + let teams = await Team.all(); + + if (showAll === "false") + { + for (let i = 0; i < teams.rows.length; i++) + { + + if (teams.rows[i].$attributes.hasOwnProperty("deleted_at")) + { + + teams.rows.splice(i, 1); + + } + } + } + + request.body.teams = teams; + + // call next to advance the request + await next() + } } module.exports = TeamFindFailSoftDeleted; diff --git a/app/Middleware/SoftDeleted/TicketFindFailSoftDeleted.js b/app/Middleware/SoftDeleted/TicketFindFailSoftDeleted.js index be4d182..2efdce9 100644 --- a/app/Middleware/SoftDeleted/TicketFindFailSoftDeleted.js +++ b/app/Middleware/SoftDeleted/TicketFindFailSoftDeleted.js @@ -2,14 +2,14 @@ class TicketFindFailSoftDeleted { - async handle({request}, next) - { - - - - // call next to advance the request - await next() - } + async handle({request}, next) + { + + + + // call next to advance the request + await next() + } } module.exports = TicketFindFailSoftDeleted; diff --git a/app/Middleware/SoftDeleted/UserFindFailSoftDeleted.js b/app/Middleware/SoftDeleted/UserFindFailSoftDeleted.js index e0d2b54..6ab29a9 100644 --- a/app/Middleware/SoftDeleted/UserFindFailSoftDeleted.js +++ b/app/Middleware/SoftDeleted/UserFindFailSoftDeleted.js @@ -4,73 +4,73 @@ const User = use('App/Models/User'); class UserFindFailSoftDeleted { - async handle ({ request }, next) - { - - let users = null; - - let { - showAll = "false", - pluck = "false", - plucks - } = request.all(); - - // if we have request to pluck from the users - if (pluck === "true") - { - // check if we have any defined plucks - if (plucks === undefined || plucks === null) - { - - // since we dont have plucks defined, but still pluck is true - // show the ID and name - users = await User.query().setVisible(['_id', 'name']).fetch(); - } - else - { - - // if we have plucks - plucks = JSON.parse(plucks); - - // check for the length - if (plucks.length >= 1) - { - - // pluck using plucks - users = await User.query().setVisible(plucks).fetch(); - } - else - { - - // or else return the default pluck. - users = await User.query().setVisible(['_id', 'name']).fetch(); - } - } - } - else - { - users = await User.all(); - } - - // if we need to see soft deleted users - if (showAll === "false") - { - for (let i = 0; i < users.rows.length; i++) - { - if (users.rows[i].$attributes.hasOwnProperty("deleted_at")) - { - - users.rows.splice(i, 1); - - } - } - } - - request.body.users = users; - - // call next to advance the request - await next() - } + async handle({request}, next) + { + + let users = null; + + let { + showAll = "false", + pluck = "false", + plucks + } = request.all(); + + // if we have request to pluck from the users + if (pluck === "true") + { + // check if we have any defined plucks + if (plucks === undefined || plucks === null) + { + + // since we dont have plucks defined, but still pluck is true + // show the ID and name + users = await User.query().setVisible(['_id', 'name']).fetch(); + } + else + { + + // if we have plucks + plucks = JSON.parse(plucks); + + // check for the length + if (plucks.length >= 1) + { + + // pluck using plucks + users = await User.query().setVisible(plucks).fetch(); + } + else + { + + // or else return the default pluck. + users = await User.query().setVisible(['_id', 'name']).fetch(); + } + } + } + else + { + users = await User.all(); + } + + // if we need to see soft deleted users + if (showAll === "false") + { + for (let i = 0; i < users.rows.length; i++) + { + if (users.rows[i].$attributes.hasOwnProperty("deleted_at")) + { + + users.rows.splice(i, 1); + + } + } + } + + request.body.users = users; + + // call next to advance the request + await next() + } } module.exports = UserFindFailSoftDeleted diff --git a/app/Middleware/SprintFindFail.js b/app/Middleware/SprintFindFail.js index 2a1fc2b..176f582 100644 --- a/app/Middleware/SprintFindFail.js +++ b/app/Middleware/SprintFindFail.js @@ -2,37 +2,48 @@ const Sprint = use('App/Models/Sprint'); -class SprintFindFail { - - async handle ({ request, response, params }, next) - { - - const { - forceDestroy = "false" - } = request.all(); - - // try to find the user from the database - let sprint = await Sprint.find(params.sprintId); - - // check for the users - if (sprint === null || sprint === undefined || (forceDestroy === "false" && sprint.$attributes.hasOwnProperty("deleted_at"))) - { - // return 400 response with the message, if the user does not exists. - return response.status(400).json({ - status: "ERROR", - message: `Sprint with the id of ${params.sprintId} could not be found.` - }); - } - - // add the user object to the request body. - request.body.sprint = sprint; - - //console.log("Passing from middleware..."); - - // carry on with the request. - await next() - - } +class SprintFindFail +{ + + async handle({request, response, params}, next) + { + + const { + forceDestroy = "false", + relations = "false" + } = request.all(); + + // try to find the user from the database + let sprint = null; + + if (relations === "true") + { + sprint = await Sprint.with(['tickets', 'project']).find(params.sprintId); + } + else + { + sprint = await Sprint.find(params.sprintId); + } + + // check for the users + if (sprint === null || sprint === undefined || (forceDestroy === "false" && sprint.$attributes.hasOwnProperty("deleted_at"))) + { + // return 400 response with the message, if the user does not exists. + return response.status(400).json({ + status: "ERROR", + message: `Sprint with the id of ${params.sprintId} could not be found.` + }); + } + + // add the user object to the request body. + request.body.sprint = sprint; + + //console.log("Passing from middleware..."); + + // carry on with the request. + await next() + + } } module.exports = SprintFindFail; diff --git a/app/Middleware/TeamFindFail.js b/app/Middleware/TeamFindFail.js index 16124a7..50dc8a5 100644 --- a/app/Middleware/TeamFindFail.js +++ b/app/Middleware/TeamFindFail.js @@ -4,42 +4,42 @@ const Team = use('App/Models/Team'); class TeamFindFail { - async handle({request, response, params}, next) - { - - // get the flags - const { - relations = "false" - } = request.all(); - - // define the variable for the team - let team = null; - - // check for request for the members - if (relations === "true") - { - // load the relationship with users. - team = await Team.with(['users', 'projects']).find(params.teamId); - } - else - { - team = await Team.find(params.teamId); - } - - // check if the team exists or team has been soft deleted - if (team === null || team.$attributes.hasOwnProperty("deleted_at")) - { - return response.status(400).json({ - status: "ERROR", - message: `A Team with id ${params.teamId} could not be found.` - }); - } - - request.body.team = team; - - // call next to advance the request - await next() - } + async handle({request, response, params}, next) + { + + // get the flags + const { + relations = "false" + } = request.all(); + + // define the variable for the team + let team = null; + + // check for request for the members + if (relations === "true") + { + // load the relationship with users. + team = await Team.with(['users', 'projects']).find(params.teamId); + } + else + { + team = await Team.find(params.teamId); + } + + // check if the team exists or team has been soft deleted + if (team === null || team.$attributes.hasOwnProperty("deleted_at")) + { + return response.status(400).json({ + status: "ERROR", + message: `A Team with id ${params.teamId} could not be found.` + }); + } + + request.body.team = team; + + // call next to advance the request + await next() + } } module.exports = TeamFindFail; diff --git a/app/Middleware/TeamFindFromBody.js b/app/Middleware/TeamFindFromBody.js index 6488cf7..82166e3 100644 --- a/app/Middleware/TeamFindFromBody.js +++ b/app/Middleware/TeamFindFromBody.js @@ -2,37 +2,39 @@ const Team = use('App/Models/Team'); -class TeamFindFromBody { - async handle({request, response}, next) { - - const { - _team_id - } = request.all(); - - if (_team_id === undefined || _team_id === null) - { - return response.status(400).json({ - status: 'ERROR', - message: `No TeamId found.` - }); - } - - let team = await Team.find(_team_id); - - if (team.$attributes.hasOwnProperty("deleted_at")) - { - return response.status(400).json({ - status: 'ERROR', - message: `No with team id: ${_team_id} has been removed or does not exists` - }); - } - - // add the request to the body. - request.body.team = team; - - // call next to advance the request - await next() - } +class TeamFindFromBody +{ + async handle({request, response}, next) + { + + const { + _team_id + } = request.all(); + + if (_team_id === undefined || _team_id === null) + { + return response.status(400).json({ + status: 'ERROR', + message: `No TeamId found.` + }); + } + + let team = await Team.find(_team_id); + + if (team.$attributes.hasOwnProperty("deleted_at")) + { + return response.status(400).json({ + status: 'ERROR', + message: `No with team id: ${_team_id} has been removed or does not exists` + }); + } + + // add the request to the body. + request.body.team = team; + + // call next to advance the request + await next() + } } module.exports = TeamFindFromBody; diff --git a/app/Middleware/TicketFindFail.js b/app/Middleware/TicketFindFail.js index de64c1b..36e9efb 100644 --- a/app/Middleware/TicketFindFail.js +++ b/app/Middleware/TicketFindFail.js @@ -4,30 +4,44 @@ const Ticket = use('App/Models/Ticket'); class TicketFindFail { - - async handle ({ request, response, params }, next) { - - // try to find the ticket from the database - let ticket = await Ticket.find(params.ticketId); - - // check for the ticket - if (ticket === null) - { - - // return 400 response with the message, if the ticket does not exists. - return response.status(400).json({ - status: "ERROR", - message: `Ticket with the id of ${params.ticketId} could not be found.` - }); - } - - // add the ticket object to the request body. - request.body.ticket = ticket; - - // carry on with the request. - await next() - - } + + async handle({request, response, params}, next) + { + + const { + relations = "false" + } = request.all(); + + // try to find the ticket from the database + let ticket = null; + + if (relations === "true") + { + ticket = await Ticket.with(['assignee', 'sprint']).find(params.ticketId); + } + else + { + ticket = await Ticket.find(params.ticketId); + } + + // check for the ticket + if (ticket === null || ticket.hasOwnProperty("deleted_at")) + { + + // return 400 response with the message, if the ticket does not exists. + return response.status(400).json({ + status: "ERROR", + message: `Ticket with the id of ${params.ticketId} could not be found.` + }); + } + + // add the ticket object to the request body. + request.body.ticket = ticket; + + // carry on with the request. + await next() + + } } module.exports = TicketFindFail; diff --git a/app/Middleware/UserFindFail.js b/app/Middleware/UserFindFail.js index 4458646..b5d3ec3 100644 --- a/app/Middleware/UserFindFail.js +++ b/app/Middleware/UserFindFail.js @@ -6,52 +6,53 @@ const Team = use("App/Models/Team"); class UserFindFail { - - async handle ({ request, response, params }, next) { - - const { - relations = "false", - } = request.all(); - - // try to find the user from the database - let user = null; - - // Loads all of the relationships associated with the user. - if (relations === "true") - { - user = await User.with(['team', 'owned_projects', 'managing_projects']).find(params.userId); - - if (user.$relations.team) - { - let team = await Team.with(['projects']).find(user.$relations.team.$attributes._id); - - user.$relations['projects'] = team.$relations.projects; - - } - } - else - { - user = await User.find(params.userId); - } - - // check for the users - if (user === null) - { - - // return 400 response with the message, if the user does not exists. - return response.status(400).json({ - status: "ERROR", - message: `User with the id of ${params.userId} could not be found.` - }); - } - - // add the user object to the request body. - request.body.user = user; - - // carry on with the request. - await next() - - } + + async handle({request, response, params}, next) + { + + const { + relations = "false", + } = request.all(); + + // try to find the user from the database + let user = null; + + // Loads all of the relationships associated with the user. + if (relations === "true") + { + user = await User.with(['team', 'owned_projects', 'managing_projects']).find(params.userId); + + if (user.$relations.team) + { + let team = await Team.with(['projects']).find(user.$relations.team.$attributes._id); + + user.$relations['projects'] = team.$relations.projects; + + } + } + else + { + user = await User.find(params.userId); + } + + // check for the users + if (user === null) + { + + // return 400 response with the message, if the user does not exists. + return response.status(400).json({ + status: "ERROR", + message: `User with the id of ${params.userId} could not be found.` + }); + } + + // add the user object to the request body. + request.body.user = user; + + // carry on with the request. + await next() + + } } module.exports = UserFindFail; diff --git a/app/Models/Ticket.js b/app/Models/Ticket.js index 19f8391..d05d12b 100644 --- a/app/Models/Ticket.js +++ b/app/Models/Ticket.js @@ -4,37 +4,37 @@ const Model = use('Model'); class Ticket extends Model { - - static get primaryKey() - { - return "_id"; - } - - static get objectIDs() - { - return ['_id', '_sprint_id']; - } - - /** - * Get the projects belongs to the ticket - * - * @return {BelongsTo} - */ - project() - { - return this.belongsTo('App/Models/Project', '_project_id', '_id'); - } - - /** - * Get the ticket type of the user - * - * @return {BelongsTo} - */ - ticketType() - { - return this.belongsTo('App/Models/TicketType', '_ticket_typ_id', '_id'); - } - + + static get primaryKey() + { + return "_id"; + } + + static get objectIDs() + { + return ['_id', '_sprint_id', '_assignee_id']; + } + + /** + * Get the ticket that the sprint belongs to + * + * @return {BelongsTo} + */ + sprint() + { + return this.belongsTo('App/Models/Sprint', '_sprint_id', '_id'); + } + + /** + * Get the assignee that the ticket has been assign to. + * + * @return {BelongsTo} + */ + assignee() + { + return this.belongsTo('App/Models/User', '_assignee_id', '_id'); + } + } module.exports = Ticket; diff --git a/app/Models/User.js b/app/Models/User.js index fef6552..50d28b5 100644 --- a/app/Models/User.js +++ b/app/Models/User.js @@ -82,6 +82,11 @@ class User extends Model return this.hasMany('App/Models/Project', '_id', '_manager_id'); } + tickets() + { + return this.hasMany('App/Models/Ticket', '_id', '_assignee_id') + } + } module.exports = User; diff --git a/app/Validators/TicketCreateUpdate.js b/app/Validators/TicketCreateUpdate.js index 64c8d5b..3ff7cc9 100644 --- a/app/Validators/TicketCreateUpdate.js +++ b/app/Validators/TicketCreateUpdate.js @@ -6,8 +6,8 @@ class TicketCreateUpdate { { return { _sprint_id: 'required|exists:sprints,_id', - //_assignee_id: 'required|exists:users,_id', - //_version_id: 'required|exists:versions,_id', + _assignee_id: 'required|exists:users,_id', + _release_id: 'required|exists:versions,_id', ticket_type: 'required', name: 'required|min:3', description: 'required|min:10', @@ -24,15 +24,14 @@ class TicketCreateUpdate { description_of_fix: 'requiredWhen:ticket_type,BUG', // common for ticket types (EPIC and STORY ONLY) - requirement_signoff_date: 'requiredWhen:tick_type,EPIC|requiredWhen:ticket_type,STORY', + requirement_sign_off_date: 'requiredWhen:tick_type,EPIC|requiredWhen:ticket_type,STORY', design_review_date: 'requiredWhen:tick_type,EPIC|requiredWhen:ticket_type,STORY', common_test_plan: 'requiredWhen:tick_type,EPIC|requiredWhen:ticket_type,STORY', definition_of_done: 'requiredWhen:tick_type,EPIC|requiredWhen:ticket_type,STORY', - } } - get validateAll () + get validateAll() { return true } diff --git a/config/auth.js b/config/auth.js index 68c8c41..afabec8 100644 --- a/config/auth.js +++ b/config/auth.js @@ -3,77 +3,77 @@ const Env = use('Env') module.exports = { - /* - |-------------------------------------------------------------------------- - | Authenticator - |-------------------------------------------------------------------------- - | - | Authentication is a combination of serializer and scheme with extra - | config to define on how to authenticate a user. - | - | Available Schemes - basic, session, jwt, api - | Available Serializers - lucid, database - | - */ - authenticator: 'jwt', - - /* - |-------------------------------------------------------------------------- - | Session - |-------------------------------------------------------------------------- - | - | Session authenticator makes use of sessions to authenticate a user. - | Session authentication is always persistent. - | - */ - session: { - serializer: 'LucidMongo', - model: 'App/Models/User', - scheme: 'session', - uid: 'email', - password: 'password' - }, - - /* - |-------------------------------------------------------------------------- - | Basic Auth - |-------------------------------------------------------------------------- - | - | The basic auth authenticator uses basic auth header to authenticate a - | user. - | - | NOTE: - | This scheme is not persistent and users are supposed to pass - | login credentials on each request. - | - */ - basic: { - serializer: 'LucidMongo', - model: 'App/Models/User', - scheme: 'basic', - uid: 'email', - password: 'password' - }, - - /* - |-------------------------------------------------------------------------- - | Jwt - |-------------------------------------------------------------------------- - | - | The jwt authenticator works by passing a jwt token on each HTTP request - | via HTTP `Authorization` header. - | - */ - jwt: { - serializer: 'LucidMongo', - model: 'App/Models/User', - token: 'App/Models/Token', - scheme: 'jwt', - uid: 'email', - password: 'password', - options: { - secret: Env.get('APP_KEY'), - expiresIn: '1d' - } - }, + /* + |-------------------------------------------------------------------------- + | Authenticator + |-------------------------------------------------------------------------- + | + | Authentication is a combination of serializer and scheme with extra + | config to define on how to authenticate a user. + | + | Available Schemes - basic, session, jwt, api + | Available Serializers - lucid, database + | + */ + authenticator: 'jwt', + + /* + |-------------------------------------------------------------------------- + | Session + |-------------------------------------------------------------------------- + | + | Session authenticator makes use of sessions to authenticate a user. + | Session authentication is always persistent. + | + */ + session: { + serializer: 'LucidMongo', + model: 'App/Models/User', + scheme: 'session', + uid: 'email', + password: 'password' + }, + + /* + |-------------------------------------------------------------------------- + | Basic Auth + |-------------------------------------------------------------------------- + | + | The basic auth authenticator uses basic auth header to authenticate a + | user. + | + | NOTE: + | This scheme is not persistent and users are supposed to pass + | login credentials on each request. + | + */ + basic: { + serializer: 'LucidMongo', + model: 'App/Models/User', + scheme: 'basic', + uid: 'email', + password: 'password' + }, + + /* + |-------------------------------------------------------------------------- + | Jwt + |-------------------------------------------------------------------------- + | + | The jwt authenticator works by passing a jwt token on each HTTP request + | via HTTP `Authorization` header. + | + */ + jwt: { + serializer: 'LucidMongo', + model: 'App/Models/User', + token: 'App/Models/Token', + scheme: 'jwt', + uid: 'email', + password: 'password', + options: { + secret: Env.get('APP_KEY'), + expiresIn: '1d' + } + }, } diff --git a/database/factory.js b/database/factory.js index 0c5667f..2c6bb8c 100644 --- a/database/factory.js +++ b/database/factory.js @@ -39,7 +39,7 @@ Factory.blueprint('App/Models/User', async (faker) => { name: faker.name(), email: faker.email(), type: "user", - password: Hash.make("sithira") + password: "sithira123" } }); diff --git a/database/seeds/DataSeeder.js b/database/seeds/DataSeeder.js index 69c5a42..18c96e0 100644 --- a/database/seeds/DataSeeder.js +++ b/database/seeds/DataSeeder.js @@ -14,24 +14,38 @@ const Factory = use('Factory'); class DataSeeder { - - async run () - { - - const release = await Factory.model('App/Models/Release') - .createMany(2); - - const users = await Factory.model('App/Models/User') - .createMany(5); - - const team = await Factory.model('App/Models/Team') - .createMany(2); - - const project = await Factory.model('App/Models/Project') - .createMany(5); - - } - + + async run() + { + + const release = await Factory.model('App/Models/Release') + .createMany(2); + + const users = await Factory.model('App/Models/User') + .createMany(5); + + const team = await Factory.model('App/Models/Team') + .createMany(2); + + const project = await Factory.model('App/Models/Project') + .createMany(5); + + for (let i = 0; i < 5; i++) + { + + for (let j = 0; j < 2; j++) + { + let sprint = await Factory.model('App/Models/Sprint').create(); + + await project[i].sprints().save(sprint); + } + + } + + const tickets = await Factory.model('App/Models/Ticket').createMany(5); + + } + } module.exports = DataSeeder; diff --git a/start/app.js b/start/app.js index 9c95fc8..2ef71a3 100644 --- a/start/app.js +++ b/start/app.js @@ -11,17 +11,17 @@ | */ const providers = [ - '@adonisjs/framework/providers/AppProvider', - '@adonisjs/framework/providers/ViewProvider', - '@adonisjs/lucid/providers/LucidProvider', - '@adonisjs/bodyparser/providers/BodyParserProvider', - '@adonisjs/cors/providers/CorsProvider', - '@adonisjs/shield/providers/ShieldProvider', - '@adonisjs/session/providers/SessionProvider', - '@adonisjs/validator/providers/ValidatorProvider', - '@adonisjs/auth/providers/AuthProvider', - 'lucid-mongo/providers/LucidMongoProvider', - 'adonis-swagger/providers/SwaggerProvider' + '@adonisjs/framework/providers/AppProvider', + '@adonisjs/framework/providers/ViewProvider', + '@adonisjs/lucid/providers/LucidProvider', + '@adonisjs/bodyparser/providers/BodyParserProvider', + '@adonisjs/cors/providers/CorsProvider', + '@adonisjs/shield/providers/ShieldProvider', + '@adonisjs/session/providers/SessionProvider', + '@adonisjs/validator/providers/ValidatorProvider', + '@adonisjs/auth/providers/AuthProvider', + 'lucid-mongo/providers/LucidMongoProvider', + 'adonis-swagger/providers/SwaggerProvider' ] /* @@ -34,9 +34,9 @@ const providers = [ | */ const aceProviders = [ - '@adonisjs/lucid/providers/MigrationsProvider', - 'lucid-mongo/providers/MigrationsProvider', - '@adonisjs/vow/providers/VowProvider' + '@adonisjs/lucid/providers/MigrationsProvider', + 'lucid-mongo/providers/MigrationsProvider', + '@adonisjs/vow/providers/VowProvider' ] /* @@ -63,4 +63,4 @@ const aliases = {} */ const commands = [] -module.exports = { providers, aceProviders, aliases, commands } +module.exports = {providers, aceProviders, aliases, commands} diff --git a/start/kernel.js b/start/kernel.js index 2fd9029..2f143ab 100644 --- a/start/kernel.js +++ b/start/kernel.js @@ -12,10 +12,10 @@ const Server = use('Server') | */ const globalMiddleware = [ - 'Adonis/Middleware/BodyParser', - 'Adonis/Middleware/Session', - 'Adonis/Middleware/Shield', - 'Adonis/Middleware/AuthInit' + 'Adonis/Middleware/BodyParser', + 'Adonis/Middleware/Session', + 'Adonis/Middleware/Shield', + 'Adonis/Middleware/AuthInit' ] /* @@ -36,28 +36,35 @@ const globalMiddleware = [ | */ const namedMiddleware = { - auth: 'App/Middleware/Auth/VerificationAuthentication', - - // Selecting - userFindFail: 'App/Middleware/UserFindFail', - projectFindFail: 'App/Middleware/ProjectFindFail', - sprintFindFail: 'App/Middleware/SprintFindFail', - ticketFindFail: 'App/Middleware/TicketFindFail', - releaseFindFail: 'App/Middleware/ReleaseFindFail', - teamFindFail: 'App/Middleware/TeamFindFail', - - // - teamFromBody: 'App/Middleware/TeamFindFromBody', - - // check before deletion - projectDeleteFail: 'App/Middleware/Deletions/ProjectDeleteFail', - sprintDeleteFail: 'App/Middleware/Deletions/SprintDeleteFail', - - // check for soft deletions - userFindFailSoftDeleted: 'App/Middleware/SoftDeleted/UserFindFailSoftDeleted', - projectFindFailSoftDeleted: 'App/Middleware/SoftDeleted/ProjectFindFailSoftDeleted', - sprintFindFailSoftDeleted: 'App/Middleware/SoftDeleted/SprintFindFailSoftDeleted', - teamFindFailSoftDeleted: 'App/Middleware/SoftDeleted/TeamFindFailSoftDeleted', + + // authenticate middleware + auth: 'App/Middleware/Auth/VerifyAuthentication', + + // ownership and role based middleware + auth_project: 'App/Middleware/Auth/VerifyProjectOwnership', + auth_sprint: 'App/Middleware/Auth/VerifyProjectSprint', + auth_ticket: 'App/Middleware/Auth/VerifyTicket', + + // Selecting + userFindFail: 'App/Middleware/UserFindFail', + projectFindFail: 'App/Middleware/ProjectFindFail', + sprintFindFail: 'App/Middleware/SprintFindFail', + ticketFindFail: 'App/Middleware/TicketFindFail', + releaseFindFail: 'App/Middleware/ReleaseFindFail', + teamFindFail: 'App/Middleware/TeamFindFail', + + // + teamFromBody: 'App/Middleware/TeamFindFromBody', + + // check before deletion + projectDeleteFail: 'App/Middleware/Deletions/ProjectDeleteFail', + sprintDeleteFail: 'App/Middleware/Deletions/SprintDeleteFail', + + // check for soft deletions + userFindFailSoftDeleted: 'App/Middleware/SoftDeleted/UserFindFailSoftDeleted', + projectFindFailSoftDeleted: 'App/Middleware/SoftDeleted/ProjectFindFailSoftDeleted', + sprintFindFailSoftDeleted: 'App/Middleware/SoftDeleted/SprintFindFailSoftDeleted', + teamFindFailSoftDeleted: 'App/Middleware/SoftDeleted/TeamFindFailSoftDeleted', } /* @@ -71,11 +78,11 @@ const namedMiddleware = { | */ const serverMiddleware = [ - 'Adonis/Middleware/Static', - 'Adonis/Middleware/Cors' + 'Adonis/Middleware/Static', + 'Adonis/Middleware/Cors' ] Server - .registerGlobal(globalMiddleware) - .registerNamed(namedMiddleware) - .use(serverMiddleware) + .registerGlobal(globalMiddleware) + .registerNamed(namedMiddleware) + .use(serverMiddleware) diff --git a/start/routes.js b/start/routes.js index 05f938d..f7f5fd8 100644 --- a/start/routes.js +++ b/start/routes.js @@ -15,27 +15,41 @@ const Route = use('Route'); -Route.on('/').render('welcome'); - const BaseUrl = '/api/v1'; -Route.get('/test', async ({request, response}) => { - - let TeamUser = use('App/Models/TeamUser'); - - return await TeamUser.with(['user', 'team', 'projects']).find("5b20afd100854933b9414bcb") - +Route.get('/', async({request, response}) => { + return response.status(200).json({ + status: "OK", + message: "Hi, Welcome to APMS-BackEnd. To use our services, please use /api/{current-version} end points.", + help: `Please use /docs for API documentation` + }) }); +Route.get(BaseUrl, async({request, response}) => { + return response.status(302).json({ + status: "ERROR", + message: 'Please refer /docs for API documentation' + }); +}); -Route.group(() => { - - //Route.get('/', ''); - - Route.post('/login', 'Auth/LoginController.login'); +Route.get('/test', async ({request, response}) => +{ + + let TeamUser = use('App/Models/TeamUser'); + + return await TeamUser.with(['user', 'team', 'projects']).find("5b20afd100854933b9414bcb") + +}); - Route.post('/logout', 'Auth/LoginController.logout'); +Route.group(() => +{ + Route.get('/', 'Auth/ProfileController.index'); + + Route.post('/login', 'Auth/LoginController.login'); + + Route.post('/logout', 'Auth/LoginController.logout'); + }).prefix('/auth'); @@ -44,154 +58,162 @@ Route.get('check', 'Auth/LoginController.check'); /** * User Routes. */ -Route.group(() => { - - // get all the users - Route.get('/', 'UserController.index') - .middleware(['userFindFailSoftDeleted']); - - // get a specified user from the database - Route.get('/:userId', 'UserController.show') - .middleware(['userFindFail']); - - // add a new user to the database. - Route.post('/', 'UserController.store') - .validator('UserStoreUpdate'); - - // update a specified user - Route.patch('/:userId', 'UserController.update') - .middleware(['userFindFail']) - .validator('UserStoreUpdate'); - - // delete a specified user ( soft or hard ) - Route.delete('/:userId', 'UserController.destroy') - .middleware(['userFindFail']); - - -}).prefix(BaseUrl + '/users'); +Route.group(() => +{ + + // get all the users + Route.get('/', 'UserController.index') + .middleware(['userFindFailSoftDeleted']); + + // get a specified user from the database + Route.get('/:userId', 'UserController.show') + .middleware(['userFindFail']); + + // add a new user to the database. + Route.post('/', 'UserController.store') + .validator('UserStoreUpdate'); + + // update a specified user + Route.patch('/:userId', 'UserController.update') + .middleware(['userFindFail']) + .validator('UserStoreUpdate'); + + // delete a specified user ( soft or hard ) + Route.delete('/:userId', 'UserController.destroy') + .middleware(['userFindFail']); + + +}).prefix(BaseUrl + '/users') + .middleware(['auth:admin']); /** * Project Routes. */ -Route.group(() => { - - // get all the projects - Route.get('/', 'ProjectController.index') - .middleware(['projectFindFailSoftDeleted']); - - // get a single project - Route.get('/:projectId', 'ProjectController.show') - .middleware(['projectFindFail']); - - // create new project in the database - Route.post('/', 'ProjectController.store') - .middleware(['teamFromBody']) - .validator('ProjectStoreUpdate'); - - // update a single project detail - Route.patch('/:projectId', 'ProjectController.update') - .middleware(['projectFindFail', 'teamFromBody']) - .validator('ProjectStoreUpdate'); - - // delete a given project ( soft or force ) - Route.delete('/:projectId', 'ProjectController.destroy') - .middleware(['projectFindFail', 'projectDeleteFail']); - +Route.group(() => +{ + + // get all the projects + Route.get('/', 'ProjectController.index') + .middleware(['projectFindFailSoftDeleted', 'auth:admin,manager,developer']); + + // get a single project + Route.get('/:projectId', 'ProjectController.show') + .middleware(['projectFindFail', 'auth_project:client,manager,developer']); + + // create new project in the database + Route.post('/', 'ProjectController.store') + .middleware(['teamFromBody', 'auth:admin,manager', 'auth_project:manager']) + .validator('ProjectStoreUpdate'); + + // update a single project detail + Route.patch('/:projectId', 'ProjectController.update') + .middleware(['projectFindFail', 'teamFromBody', 'auth_project:manager']) + .validator('ProjectStoreUpdate'); + + // delete a given project ( soft or force ) + Route.delete('/:projectId', 'ProjectController.destroy') + .middleware(['projectFindFail', 'projectDeleteFail', 'auth_project:manager']); + }).prefix(BaseUrl + '/projects') - .middleware(['auth:admin']); + .middleware(['auth']); /** * Team Routes */ -Route.group(() => { - - Route.get('/', 'TeamController.index') - .middleware(['teamFindFailSoftDeleted']); - - Route.get('/:teamId', 'TeamController.show') - .middleware(['teamFindFail']); - - Route.post('/', 'TeamController.store') - .validator(['TeamStoreUpdate']); - - Route.post('/:teamId/:userId/', 'TeamController.addMember') - .middleware(['teamFindFail', 'userFindFail']); - - Route.delete('/:teamId/:userId/', 'TeamController.removeMember') - .middleware(['teamFindFail', 'userFindFail']); - - Route.delete('/:teamId', 'TeamController.destroy') - .middleware(['teamFindFail']); - - -}).prefix(BaseUrl + '/teams'); +Route.group(() => +{ + + Route.get('/', 'TeamController.index') + .middleware(['teamFindFailSoftDeleted']); + + Route.get('/:teamId', 'TeamController.show') + .middleware(['teamFindFail']); + + Route.post('/', 'TeamController.store') + .validator(['TeamStoreUpdate']); + + Route.post('/:teamId/:userId/', 'TeamController.addMember') + .middleware(['teamFindFail', 'userFindFail']); + + Route.delete('/:teamId/:userId/', 'TeamController.removeMember') + .middleware(['teamFindFail', 'userFindFail']); + + Route.delete('/:teamId', 'TeamController.destroy') + .middleware(['teamFindFail', 'auth:admin']); + + +}).prefix(BaseUrl + '/teams') + .middleware(['auth:admin,manager']); /** * Project Sprint Routes. */ -Route.group(() => { - - Route.get('/', 'SprintController.index'); - //.middleware(['sprintFindFailSoftDeleted']); - - Route.get('/:sprintId', 'SprintController.show') - .middleware(['sprintFindFail']); - - Route.post('/', 'SprintController.store') - .validator('SprintCreateUpdate'); - - Route.patch('/:sprintId', 'SprintController.update') - .middleware(['sprintFindFail']) - .validator('SprintCreateUpdate'); - - Route.delete('/:sprintId', 'SprintController.destroy') - .middleware(['sprintFindFail', 'sprintDeleteFail']); - +Route.group(() => +{ + + Route.get('/', 'SprintController.index'); + //.middleware(['sprintFindFailSoftDeleted']); + + Route.get('/:sprintId', 'SprintController.show') + .middleware(['sprintFindFail']); + + Route.post('/', 'SprintController.store') + .validator('SprintCreateUpdate'); + + Route.patch('/:sprintId', 'SprintController.update') + .middleware(['sprintFindFail']) + .validator('SprintCreateUpdate'); + + Route.delete('/:sprintId', 'SprintController.destroy') + .middleware(['sprintFindFail', 'sprintDeleteFail']); + }).prefix(BaseUrl + '/projects/:projectId/sprints') - .middleware(['projectFindFail']); + .middleware(['projectFindFail']); /** * Project Release Routes */ -Route.group(() => { - - Route.get('/', 'ReleaseController.index'); - - Route.post('/', 'ReleaseController.store') - .validator(['releaseCreateUpdate']); - - Route.get('/:releaseId', 'ReleaseController.show') - .middleware(['releaseFindFail']); - - Route.patch('/:releaseId', 'ReleaseController.update') - .middleware(['releaseFindFail']) - .validator('releaseCreateUpdate'); - - Route.delete('/:releaseId', 'ReleaseController.update') - .middleware(['releaseFindFail']); - +Route.group(() => +{ + + Route.get('/', 'ReleaseController.index'); + + Route.post('/', 'ReleaseController.store') + .validator(['releaseCreateUpdate']); + + Route.get('/:releaseId', 'ReleaseController.show') + .middleware(['releaseFindFail']); + + Route.patch('/:releaseId', 'ReleaseController.update') + .middleware(['releaseFindFail']) + .validator('releaseCreateUpdate'); + + Route.delete('/:releaseId', 'ReleaseController.update') + .middleware(['releaseFindFail']); + }).prefix(BaseUrl + '/projects/:projectId/releases') - .middleware(['projectFindFail']); + .middleware(['projectFindFail', 'auth_project:admin,manager']); /** * Ticket C.R.U.D Routes */ -Route.group(() => { - - Route.get('/', 'TicketController.index'); - - Route.get('/:ticketId', 'TicketController.show') - .middleware(['ticketFindFail']); - - Route.post('/', 'TicketController.store') - .validator('TicketCreateUpdate'); - - Route.patch('/:ticketId', 'TicketController.update') - .middleware(['ticketFindFail']); - - Route.delete('/:ticketId', 'TicketController.destroy') - .middleware(['ticketFindFail']); - +Route.group(() => +{ + + Route.get('/', 'TicketController.index'); + + Route.get('/:ticketId', 'TicketController.show') + .middleware(['ticketFindFail', 'auth_ticket']); + + Route.post('/', 'TicketController.store') + .validator('TicketCreateUpdate', 'auth_project:manager,developer'); + + Route.patch('/:ticketId', 'TicketController.update') + .middleware(['ticketFindFail', 'auth_ticket']); + + Route.delete('/:ticketId', 'TicketController.destroy') + .middleware(['ticketFindFail', 'auth_ticket', 'auth_project:manager']); + }).prefix(BaseUrl + '/projects/:projectId/sprints/:sprintId/tickets') - .middleware(['projectFindFail', 'sprintFindFail']); + .middleware(['projectFindFail', 'sprintFindFail']);