Skip to content

Commit

Permalink
feat(tripRequest): user can make a trip request
Browse files Browse the repository at this point in the history
- create a controller for handling trip requests
- create a validation rule to handle the trip request validation
- add a file to verify jsonwebtoken
- create trip request services to abstract models for the trip request controller

[Delivers #167750059]
  • Loading branch information
feobaby committed Sep 15, 2019
1 parent d580d86 commit 51c036f
Show file tree
Hide file tree
Showing 35 changed files with 1,188 additions and 52 deletions.
3 changes: 3 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ version: "2"
exclude_patterns:
- "src/database/"
- "src/models/"
- "src/middlewares/"
- "src/controllers/tripController.js"
- "src/services/requestService.js"
- "**/test/"
- "./src/utils/emailTemplates/confirmAccountTemplate.js"
- "./src/utils/emailTemplates/passwordRecoveryTemplate.js"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"clean": "rm -rf build && mkdir build",
"build-babel": "babel -d ./build ./src -s",
"build": "npm run clean && npm run build-babel",
"pre-dev": "cross-env NODE_ENV=development npm run migrate && cross-env NODE_ENV=development npm run seed",
"pre-test": "cross-env NODE_ENV=test npm run migrate && cross-env NODE_ENV=test npm run seed",
"undo-pre-test": "cross-env NODE_ENV=test npm run undo-migrate",
"spec": "npm run undo-pre-test && npm run pre-test && npm test",
Expand Down Expand Up @@ -81,4 +82,4 @@
"**src/test/**"
]
}
}
}
5 changes: 4 additions & 1 deletion src/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import UsersController from './users';
import ResetPasswordController from './resetPassword';
import AccommodationController from './accommodationController';
import RoomController from './roomController';
import RequestController from './requestController';
import TripController from './tripController';

export {
UsersController, ResetPasswordController,
AccommodationController, RoomController
AccommodationController, RoomController,
RequestController, TripController
};
133 changes: 133 additions & 0 deletions src/controllers/requestController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import RequestService from '../services/requestService';
import {
getCallbackUrls, messages, status, successResponse, errorResponse,
} from '../utils/index';

import * as services from '../services';
import models from '../models';

const { Requests } = models;

const { baseUrl } = getCallbackUrls;
/**
* @class RequestController
* @description Controllers for Request
* @exports RequestController
*/
export default class RequestController {
/**
* @method createRequest
* @description Method for users to make a request
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @returns {object} response body object
*/
static async createRequest(req, res) {
const { userId } = req.user;
const { departmentId } = req.params;
const { lineManagerMail } = req.body;
try {
const options = { userId, departmentId, lineManagerMail };
const result = await RequestService.createRequest(options);
const url = `${baseUrl}/users/tripRequest`;
await services.sendEmail(lineManagerMail, 'tripRequest', { url });
return successResponse(res, status.created, messages.requests.success, result);
} catch (error) {
return errorResponse(res, status.error, messages.requests.error);
}
}


/**
* @method getAllTripRequests
* @description Method for users to get all trip requests
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @returns {object} response body object
*/
static async getAllTripRequests(req, res) {
const { userId } = req.user;
try {
const request = await RequestService.getAllTripRequests(userId);
if (request.length > 0) {
return successResponse(res, status.success, request);
}
return errorResponse(res, status.notfound, messages.getRequests.error);
} catch (error) {
return errorResponse(res, status.error, messages.authentication.error);
}
}

/**
* @method getATripRequest
* @description Method for users to get a single request
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @returns {object} response body object
*/
static async getATripRequest(req, res) {
const { id } = req.params;
const { userId } = req.user;
try {
const result = await RequestService.getATripRequest(id, userId);
if (!result) {
return errorResponse(res, status.notfound, messages.getSingleRequests.notFound);
}
return successResponse(res, status.success, result);
} catch (error) {
return errorResponse(res, status.error, messages.authentication.error);
}
}


/**
* @method deleteRequest
* @description Method for users to delete a request
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @returns {object} response body object
*/
static async deleteRequest(req, res) {
const { id } = req.params;
const { userId } = req.user;
try {
const check = await Requests.findOne({ where: { id, userId } });
if (!check) {
return errorResponse(res, status.notfound, messages.deleteRequests.notFound);
}
if (check.status !== 'pending') {
return errorResponse(res, status.unprocessable, messages.deleteRequests.access);
}
await Requests.destroy({ where: { id, userId } });
return successResponse(res, status.success, messages.deleteRequests.success);
} catch (error) {
return errorResponse(res, status.error, messages.authentication.error);
}
}

/**
* @method managerGetRequest
* @description Method for a manager to get requests pertaining to her department
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @returns {object} response body object
*/
static async managerGetRequest(req, res) {
const { departmentId } = req.params;
if (!req.query.status) {
const result = await RequestService.managerGetTheRequest(departmentId);
return successResponse(res, 200, messages.managerRequests.success, result);
}
// eslint-disable-next-line no-shadow
const { status } = req.query;
try {
const result = await RequestService.managerGetRequest(departmentId, status);
if (!result) {
return errorResponse(res, 404, messages.getRequests.error);
}
return successResponse(res, 200, result);
} catch (error) {
return errorResponse(res, 500, messages.authentication.error);
}
}
}
2 changes: 2 additions & 0 deletions src/controllers/roomController.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class RoomController {
}, { where: { id: roomId } });
return successResponse(res, 200, 'Room updated');
} catch (error) {
console.log(error);
return errorResponse(res, 500, 'Error updating room');
}
}
Expand All @@ -75,6 +76,7 @@ class RoomController {
await Rooms.destroy({ where: { id: roomId } });
return successResponse(res, 200, 'Room deleted');
} catch (error) {
console.log(error);
return errorResponse(res, 500, 'Error deleting room');
}
}
Expand Down
79 changes: 79 additions & 0 deletions src/controllers/tripController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import TripService from '../services/tripService';
import {
messages, status, successResponse, errorResponse
} from '../utils/index';
import models from '../models';

const { Requests } = models;

/**
* @class TripController
* @description Controllers for Trips
* @exports TripController
*/
export default class TripController {
/**
* @method createTrip
* @description Method for users to make a trip request
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @returns {object} response body object
*/
static async createTrip(req, res) {
const { requestId } = req.params;
const {
origin, destination, departureDate, returnDate,
travelReasons, typeOfTrip, roomId, accommodationId
} = req.body;
const options = {
requestId,
origin,
destination,
departureDate,
returnDate,
travelReasons,
typeOfTrip,
roomId,
accommodationId
};
try {
const result = await TripService.createTrip(options);
return successResponse(res, status.created, messages.requests.success, result);
} catch (error) {
return errorResponse(res, status.error, messages.requests.error);
}
}

/**
* @method updateTrip
* @description Method for users to update a trip request
* @param {object} req - The Request Object
* @param {object} res - The Response Object
* @returns {object} response body object
*/
static async updateTrip(req, res) {
const { requestId, tripId } = req.params;
const { userId } = req.user;
try {
const {
origin, destination, departureDate, returnDate,
travelReasons, typeOfTrip, roomId, accommodationId,
} = req.body;
const options = {
origin, destination, departureDate, returnDate, travelReasons, typeOfTrip, roomId, accommodationId,
};
const requests = await Requests.findByPk(requestId);
if (requests.status !== 'pending') {
return errorResponse(res, status.unprocessable, messages.updateRequests.access);
}
await Requests.findOne({ where: { userId } });
if (requests.userId !== userId) {
return errorResponse(res, status.unauthorized, messages.updateTrips.unauthorized);
}
const result = await TripService.updateTrip(tripId, options);
return successResponse(res, status.success, messages.updateRequests.success, result);
} catch (error) {
return errorResponse(res, status.error, messages.updateRequests.error);
}
}
}
4 changes: 2 additions & 2 deletions src/controllers/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export default class UsersController {
static async registerUser(req, res) {
try {
const { email } = req.body;
const userExits = await models.Users.findOne({ where: { email } });
if (userExits) {
const userExists = await models.Users.findOne({ where: { email } });
if (userExists) {
return conflictResponse(res, status.conflict, messages.signUp.conflict);
}

Expand Down
12 changes: 8 additions & 4 deletions src/database/migrations/create-6-requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,30 @@ export default {
allowNull: false,
defaultValue: 'pending',
},
accommodationId: {
userId: {
type: Sequelize.DataTypes.UUID,
allowNull: false,
references: {
model: 'Accommodations',
model: 'Users',
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
},
userId: {
departmentId: {
type: Sequelize.DataTypes.UUID,
allowNull: false,
references: {
model: 'Users',
model: 'Departments',
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
},
lineManagerMail: {
type: Sequelize.DataTypes.STRING,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
Expand Down
24 changes: 24 additions & 0 deletions src/database/migrations/create-8-trips.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export default {
type: Sequelize.STRING,
allowNull: false
},
typeOfTrip: {
type: Sequelize.ENUM('One Way', 'Return', 'Multi-City'),
allowNull: false
},
requestId: {
type: Sequelize.DataTypes.UUID,
allowNull: false,
Expand All @@ -34,6 +38,26 @@ export default {
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
accommodationId: {
type: Sequelize.DataTypes.UUID,
allowNull: false,
references: {
model: 'Accommodations',
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
},
roomId: {
type: Sequelize.DataTypes.UUID,
allowNull: false,
references: {
model: 'Rooms',
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
},
createdAt: {
Expand Down
4 changes: 4 additions & 0 deletions src/database/seeders/create-1-department.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export default {
{
id: '36da1ce3-8e1f-4b0f-8e15-1189d8231ef2',
name: 'Software Engineering'
},
{
id: 'ac99e4b1-b145-403e-aae0-96d7863eaf7d',
name: 'Finance Department'
}
],
{}
Expand Down
24 changes: 24 additions & 0 deletions src/database/seeders/create-2-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@ export default {
isVerified: true,
createdAt: new Date(),
updatedAt: new Date()
},
{
id: '2e2e18b9-8bf8-43c3-b19a-c36477dc47b6',
email: 'kelechi@gmail.com',
password: hashPassword('kelechi'),
isVerified: true,
createdAt: new Date(),
updatedAt: new Date()
},
{
id: 'f889348b-abb2-4cda-bec1-04251163ce64',
email: 'funmiolaiya9@gmail.com',
password: hashPassword('funmilayo'),
isVerified: true,
createdAt: new Date(),
updatedAt: new Date()
},
{
id: 'f1daf099-62cf-4851-a600-7d5321f9b5d4',
email: 'ayooyewo@gmail.com',
password: hashPassword('ayo1234'),
isVerified: true,
createdAt: new Date(),
updatedAt: new Date()
}
],
{}
Expand Down
Loading

0 comments on commit 51c036f

Please sign in to comment.