Skip to content

Commit 51f7daa

Browse files
committed
feat(tripRequest): user can make a trip request
- 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]
1 parent d580d86 commit 51f7daa

34 files changed

+1294
-52
lines changed

.codeclimate.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ version: "2"
22
exclude_patterns:
33
- "src/database/"
44
- "src/models/"
5+
- "src/middlewares/"
6+
- "src/controllers/tripController.js"
7+
- "src/services/requestService.js"
58
- "**/test/"
69
- "./src/utils/emailTemplates/confirmAccountTemplate.js"
710
- "./src/utils/emailTemplates/passwordRecoveryTemplate.js"

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"clean": "rm -rf build && mkdir build",
88
"build-babel": "babel -d ./build ./src -s",
99
"build": "npm run clean && npm run build-babel",
10+
"pre-dev": "cross-env NODE_ENV=development npm run migrate && cross-env NODE_ENV=development npm run seed",
1011
"pre-test": "cross-env NODE_ENV=test npm run migrate && cross-env NODE_ENV=test npm run seed",
1112
"undo-pre-test": "cross-env NODE_ENV=test npm run undo-migrate",
1213
"spec": "npm run undo-pre-test && npm run pre-test && npm test",
@@ -81,4 +82,4 @@
8182
"**src/test/**"
8283
]
8384
}
84-
}
85+
}

src/controllers/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ import UsersController from './users';
22
import ResetPasswordController from './resetPassword';
33
import AccommodationController from './accommodationController';
44
import RoomController from './roomController';
5+
import RequestController from './requestController';
6+
import TripController from './tripController';
57

68
export {
79
UsersController, ResetPasswordController,
8-
AccommodationController, RoomController
10+
AccommodationController, RoomController,
11+
RequestController, TripController
912
};

src/controllers/requestController.js

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import RequestService from '../services/requestService';
2+
import {
3+
getCallbackUrls, messages, status, successResponse, errorResponse,
4+
} from '../utils/index';
5+
6+
import * as services from '../services';
7+
import models from '../models';
8+
9+
const { Requests } = models;
10+
11+
const { baseUrl } = getCallbackUrls;
12+
/**
13+
* @class RequestController
14+
* @description Controllers for Request
15+
* @exports RequestController
16+
*/
17+
export default class RequestController {
18+
/**
19+
* @method createRequest
20+
* @description Method for users to make a request
21+
* @param {object} req - The Request Object
22+
* @param {object} res - The Response Object
23+
* @returns {object} response body object
24+
*/
25+
static async createRequest(req, res) {
26+
const { userId } = req.user;
27+
const { departmentId } = req.params;
28+
const { lineManagerMail } = req.body;
29+
try {
30+
const options = { userId, departmentId, lineManagerMail };
31+
const result = await RequestService.createRequest(options);
32+
const url = `${baseUrl}/users/tripRequest`;
33+
await services.sendEmail(lineManagerMail, 'tripRequest', { url });
34+
return successResponse(res, status.created, messages.requests.success, result);
35+
} catch (error) {
36+
return errorResponse(res, status.error, messages.requests.error);
37+
}
38+
}
39+
40+
41+
/**
42+
* @method getAllTripRequests
43+
* @description Method for users to get all trip requests
44+
* @param {object} req - The Request Object
45+
* @param {object} res - The Response Object
46+
* @returns {object} response body object
47+
*/
48+
static async getAllTripRequests(req, res) {
49+
const { userId } = req.user;
50+
try {
51+
const request = await RequestService.getAllTripRequests(userId);
52+
if (request.length > 0) {
53+
return successResponse(res, status.success, request);
54+
}
55+
return errorResponse(res, status.notfound, messages.getRequests.error);
56+
} catch (error) {
57+
return errorResponse(res, status.error, messages.authentication.error);
58+
}
59+
}
60+
61+
/**
62+
* @method getATripRequest
63+
* @description Method for users to get a single request
64+
* @param {object} req - The Request Object
65+
* @param {object} res - The Response Object
66+
* @returns {object} response body object
67+
*/
68+
static async getATripRequest(req, res) {
69+
const { id } = req.params;
70+
const { userId } = req.user;
71+
try {
72+
const result = await RequestService.getATripRequest(id, userId);
73+
if (!result) {
74+
return errorResponse(res, status.notfound, messages.getSingleRequests.notFound);
75+
}
76+
return successResponse(res, status.success, result);
77+
} catch (error) {
78+
return errorResponse(res, status.error, messages.authentication.error);
79+
}
80+
}
81+
82+
83+
/**
84+
* @method deleteRequest
85+
* @description Method for users to delete a request
86+
* @param {object} req - The Request Object
87+
* @param {object} res - The Response Object
88+
* @returns {object} response body object
89+
*/
90+
static async deleteRequest(req, res) {
91+
const { id } = req.params;
92+
const { userId } = req.user;
93+
try {
94+
const check = await Requests.findOne({ where: { id, userId } });
95+
if (!check) {
96+
return errorResponse(res, status.notfound, messages.deleteRequests.notFound);
97+
}
98+
if (check.status !== 'pending') {
99+
return errorResponse(res, status.unprocessable, messages.deleteRequests.access);
100+
}
101+
await Requests.destroy({ where: { id, userId } });
102+
return successResponse(res, status.success, messages.deleteRequests.success);
103+
} catch (error) {
104+
return errorResponse(res, status.error, messages.authentication.error);
105+
}
106+
}
107+
108+
/**
109+
* @method managerGetRequest
110+
* @description Method for a manager to get requests pertaining to her department
111+
* @param {object} req - The Request Object
112+
* @param {object} res - The Response Object
113+
* @returns {object} response body object
114+
*/
115+
static async managerGetRequest(req, res) {
116+
const { departmentId } = req.department;
117+
if (!req.query.status) {
118+
const result = await RequestService.managerGetTheRequest(departmentId);
119+
return successResponse(res, 200, messages.managerRequests.success, result);
120+
}
121+
// eslint-disable-next-line no-shadow
122+
const { status } = req.query;
123+
try {
124+
const result = await RequestService.managerGetRequest(departmentId, status);
125+
if (!result) {
126+
return errorResponse(res, 404, messages.getRequests.error);
127+
}
128+
return successResponse(res, 200, result);
129+
} catch (error) {
130+
return errorResponse(res, 500, messages.authentication.error);
131+
}
132+
}
133+
}

src/controllers/tripController.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import TripService from '../services/tripService';
2+
import {
3+
messages, status, successResponse, errorResponse
4+
} from '../utils/index';
5+
import models from '../models';
6+
7+
const { Requests } = models;
8+
9+
/**
10+
* @class TripController
11+
* @description Controllers for Trips
12+
* @exports TripController
13+
*/
14+
export default class TripController {
15+
/**
16+
* @method createTrip
17+
* @description Method for users to make a trip request
18+
* @param {object} req - The Request Object
19+
* @param {object} res - The Response Object
20+
* @returns {object} response body object
21+
*/
22+
static async createTrip(req, res) {
23+
const { requestId } = req.params;
24+
const {
25+
origin, destination, departureDate, returnDate,
26+
travelReasons, typeOfTrip, roomId, accommodationId
27+
} = req.body;
28+
const options = {
29+
requestId,
30+
origin,
31+
destination,
32+
departureDate,
33+
returnDate,
34+
travelReasons,
35+
typeOfTrip,
36+
roomId,
37+
accommodationId
38+
};
39+
try {
40+
const result = await TripService.createTrip(options);
41+
return successResponse(res, status.created, messages.requests.success, result);
42+
} catch (error) {
43+
return errorResponse(res, status.error, messages.requests.error);
44+
}
45+
}
46+
47+
/**
48+
* @method updateTrip
49+
* @description Method for users to update a trip request
50+
* @param {object} req - The Request Object
51+
* @param {object} res - The Response Object
52+
* @returns {object} response body object
53+
*/
54+
static async updateTrip(req, res) {
55+
const { requestId, tripId } = req.params;
56+
const { userId } = req.user;
57+
try {
58+
const {
59+
origin, destination, departureDate, returnDate,
60+
travelReasons, typeOfTrip, roomId, accommodationId,
61+
} = req.body;
62+
const options = {
63+
origin, destination, departureDate, returnDate, travelReasons, typeOfTrip, roomId, accommodationId,
64+
};
65+
const requests = await Requests.findByPk(requestId);
66+
if (requests.status !== 'pending') {
67+
return errorResponse(res, status.unprocessable, messages.updateRequests.access);
68+
}
69+
if (requests.userId !== userId) {
70+
return errorResponse(res, status.unauthorized, messages.updateTrips.unauthorized);
71+
}
72+
const result = await TripService.updateTrip(tripId, options);
73+
return successResponse(res, status.success, messages.updateRequests.success, result);
74+
} catch (error) {
75+
return errorResponse(res, status.error, messages.updateRequests.error);
76+
}
77+
}
78+
}

src/controllers/users.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ export default class UsersController {
2323
static async registerUser(req, res) {
2424
try {
2525
const { email } = req.body;
26-
const userExits = await models.Users.findOne({ where: { email } });
27-
if (userExits) {
26+
const userExists = await models.Users.findOne({ where: { email } });
27+
if (userExists) {
2828
return conflictResponse(res, status.conflict, messages.signUp.conflict);
2929
}
3030

src/database/migrations/create-6-requests.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,30 @@ export default {
1111
allowNull: false,
1212
defaultValue: 'pending',
1313
},
14-
accommodationId: {
14+
userId: {
1515
type: Sequelize.DataTypes.UUID,
1616
allowNull: false,
1717
references: {
18-
model: 'Accommodations',
18+
model: 'Users',
1919
key: 'id',
2020
},
2121
onUpdate: 'CASCADE',
2222
onDelete: 'SET NULL'
2323
},
24-
userId: {
24+
departmentId: {
2525
type: Sequelize.DataTypes.UUID,
2626
allowNull: false,
2727
references: {
28-
model: 'Users',
28+
model: 'Departments',
2929
key: 'id',
3030
},
3131
onUpdate: 'CASCADE',
3232
onDelete: 'SET NULL'
3333
},
34+
lineManagerMail: {
35+
type: Sequelize.DataTypes.STRING,
36+
allowNull: false
37+
},
3438
createdAt: {
3539
allowNull: false,
3640
type: Sequelize.DATE,

src/database/migrations/create-8-trips.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ export default {
2626
type: Sequelize.STRING,
2727
allowNull: false
2828
},
29+
typeOfTrip: {
30+
type: Sequelize.ENUM('One Way', 'Return', 'Multi-City'),
31+
allowNull: false
32+
},
2933
requestId: {
3034
type: Sequelize.DataTypes.UUID,
3135
allowNull: false,
@@ -34,6 +38,26 @@ export default {
3438
key: 'id',
3539
},
3640
onUpdate: 'CASCADE',
41+
onDelete: 'CASCADE'
42+
},
43+
accommodationId: {
44+
type: Sequelize.DataTypes.UUID,
45+
allowNull: false,
46+
references: {
47+
model: 'Accommodations',
48+
key: 'id',
49+
},
50+
onUpdate: 'CASCADE',
51+
onDelete: 'SET NULL'
52+
},
53+
roomId: {
54+
type: Sequelize.DataTypes.UUID,
55+
allowNull: false,
56+
references: {
57+
model: 'Rooms',
58+
key: 'id',
59+
},
60+
onUpdate: 'CASCADE',
3761
onDelete: 'SET NULL'
3862
},
3963
createdAt: {

src/database/seeders/create-1-department.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ export default {
55
{
66
id: '36da1ce3-8e1f-4b0f-8e15-1189d8231ef2',
77
name: 'Software Engineering'
8+
},
9+
{
10+
id: 'ac99e4b1-b145-403e-aae0-96d7863eaf7d',
11+
name: 'Finance Department'
812
}
913
],
1014
{}

src/database/seeders/create-2-user.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,38 @@ export default {
2828
isVerified: true,
2929
createdAt: new Date(),
3030
updatedAt: new Date()
31+
},
32+
{
33+
id: '2e2e18b9-8bf8-43c3-b19a-c36477dc47b6',
34+
35+
password: hashPassword('kelechi'),
36+
isVerified: true,
37+
createdAt: new Date(),
38+
updatedAt: new Date()
39+
},
40+
{
41+
id: 'f889348b-abb2-4cda-bec1-04251163ce64',
42+
43+
password: hashPassword('samson'),
44+
isVerified: true,
45+
createdAt: new Date(),
46+
updatedAt: new Date()
47+
},
48+
{
49+
id: 'f1daf099-62cf-4851-a600-7d5321f9b5d4',
50+
51+
password: hashPassword('ayo1234'),
52+
isVerified: true,
53+
createdAt: new Date(),
54+
updatedAt: new Date()
55+
},
56+
{
57+
id: '36bc32ea-43e4-40a8-9968-e281981ca0fe',
58+
59+
password: hashPassword('dele1234'),
60+
isVerified: true,
61+
createdAt: new Date(),
62+
updatedAt: new Date()
3163
}
3264
],
3365
{}

0 commit comments

Comments
 (0)