Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#167749958 Return trip endpoint #27

Merged
merged 1 commit into from
Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/config/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@
"type": "string",
"format": "date"
},
"returnDate": {
"type": "string",
"format": "date"
},
"reason": {
"type": "string"
},
Expand Down Expand Up @@ -242,13 +246,17 @@
"destination": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["one-way", "return"]
},
"departureDate": {
"type": "string",
"format": "date"
},
"type": {
"returnDate": {
"type": "string",
"enum": ["one-way", "return"]
"format": "date"
},
"reason": {
"type": "string"
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/RequestController.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ export default class RequestController {
static bookTrip(req, res) {
const userId = req.user.id;
const {
origin, destination, departureDate, reason, accommodation, type
origin, destination, departureDate, reason, accommodation, type, returnDate
} = req.body;
let request = {
origin, destination, departureDate, reason, accommodation, userId, type
origin, destination, departureDate, reason, accommodation, userId, type, returnDate
};
request = Helper.formatRequest(request);
RequestService.bookTrip(request).then(response => {
Expand Down
4 changes: 2 additions & 2 deletions src/database/seeders/20190909033022-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = {
firstName: 'Tosin',
lastName: 'Alabi',
email: 'tosin@mail.com',
password: 'tosin1234',
password: '$2b$10$mnxlDiPZl.aUHVJJbe3foO7QKKcKqFuhwSwk4XbFQTAp1mdSG3TIC',
isVerified: true,
createdAt: new Date(),
updatedAt: new Date()
Expand All @@ -21,7 +21,7 @@ module.exports = {
firstName: 'Frank',
lastName: 'Lampard',
email: 'frank@gmail.com',
password: 'frank1234',
password: 'Frank1234',
isVerified: false,
createdAt: new Date(),
updatedAt: new Date()
Expand Down
12 changes: 12 additions & 0 deletions src/database/seeders/20190911231139-request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
up: queryInterface => queryInterface.bulkInsert('Requests', [{
userId: 1,
origin: 'New York',
destination: 'Tokyo',
type: 'one-way',
departureDate: '2019-12-25',
reason: 'New office',
createdAt: new Date(),
updatedAt: new Date()
}], {})
};
13 changes: 9 additions & 4 deletions src/middlewares/requestValidations.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ import Helper from '../utils/Helper';
*/
const validateTripRequest = (req, res, next) => {
const userId = req.user.id;
let { departureDate } = req.body;
const { type } = req.body;
let { departureDate, returnDate } = req.body;
departureDate = new Date(departureDate).toISOString();
if (type === 'return') returnDate = new Date(returnDate).toISOString();
models.Request.findAll({ where: { userId } }).then(data => {
const conflicts = Helper.checkTrip(data, departureDate);
return conflicts;
if (data.length > 0) {
const conflicts = Helper.checkTrip(data, departureDate, returnDate);
return conflicts;
}
}).then(messages => {
if (messages && messages.length > 0) {
Responses.setError(409, 'you already have a trip booked around this pe'
Expand All @@ -41,10 +45,11 @@ const validateTripRequest = (req, res, next) => {
* @returns {object} JSON response
*/
const validateTrip = (req, res, next) => {
const { type } = req.body;
let { departureDate, returnDate } = req.body;
departureDate = new Date(departureDate).toISOString();
returnDate = returnDate ? returnDate.trim() : undefined;
if (returnDate) {
if (type === 'one-way' && returnDate) {
Responses.setError(400, 'you cannot have returnDate for a one-way trip');
return Responses.send(res);
}
Expand Down
5 changes: 2 additions & 3 deletions src/routes/userRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ import validation from '../middlewares/validation';
import userValidations from '../middlewares/userValidations';

const userRoute = express.Router();
const { validate } = validation;

userRoute.post(
'/users/signup',
validate('signup'),
validation.validate('signup'),
userValidations.emailExists,
UserController.signup
);

userRoute.post(
'/users/signin',
validate('signin'),
validation.validate('signin'),
userValidations.validateLogin,
UserController.signin
);
Expand Down
37 changes: 19 additions & 18 deletions src/tests/request.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ describe('/POST Requests route', () => {
before(done => {
chai
.request(app)
.post('/api/v1/users/signup')
.post('/api/v1/users/signin')
.send({
email: 'viola415kjk0@gmail.com',
firstName: 'Viola',
lastName: 'Violin',
password: 'Viola-1003',
email: 'tosin@mail.com',
password: 'Tosin1234',
})
.end((err, res) => {
userToken = res.body.data.token;
Expand Down Expand Up @@ -57,6 +55,7 @@ describe('/POST Requests route', () => {
destination: ' London ',
type: 'one-way',
departureDate: '2019-10-11',
returnDate: '2019/11/10',
reason: ' dgfgfg hfhfhf kfkfkf ',
accommodation: ' bbbv '
})
Expand All @@ -77,8 +76,9 @@ describe('/POST Requests route', () => {
.send({
origin: '',
destination: ' London ',
type: 'return',
type: 'one-wy',
departureDate: '2019/160/11',
returnDate: '2029/22/33',
reason: ' dgfgfg hfhfhf kfkfkf ',
accommodation: ' bbbv '
})
Expand All @@ -91,7 +91,7 @@ describe('/POST Requests route', () => {
});
});

it('should return an error if departure date has gone by already', done => {
it('should return an error if one-way trip has return date', done => {
chai
.request(app)
.post('/api/v1/requests')
Expand All @@ -100,7 +100,8 @@ describe('/POST Requests route', () => {
origin: 'Lagos',
destination: ' London ',
type: 'one-way',
departureDate: '2019-08-11',
departureDate: '2019-10-11',
returnDate: '2019-11-11',
reason: ' dgfgfg hfhfhf kfkfkf ',
accommodation: ' bbbv '
})
Expand All @@ -109,12 +110,12 @@ describe('/POST Requests route', () => {
expect(res.body).to.be.an('object');
expect(res.body).to.have.property('status').eql('error');
expect(res.body).to.have.property('message')
.eql('you cannot go back in time');
.eql('you cannot have returnDate for a one-way trip');
done(err);
});
});

it('should return an error if one-way trip has return date', done => {
it('should return an error if departure date has gone already', done => {
chai
.request(app)
.post('/api/v1/requests')
Expand All @@ -123,8 +124,7 @@ describe('/POST Requests route', () => {
origin: 'Lagos',
destination: ' London ',
type: 'one-way',
departureDate: '2019-10-11',
returnDate: '2019-11-11',
departureDate: '2019-08-11',
reason: ' dgfgfg hfhfhf kfkfkf ',
accommodation: ' bbbv '
})
Expand All @@ -133,7 +133,7 @@ describe('/POST Requests route', () => {
expect(res.body).to.be.an('object');
expect(res.body).to.have.property('status').eql('error');
expect(res.body).to.have.property('message')
.eql('you cannot have returnDate for a one-way trip');
.eql('you cannot go back in time');
done(err);
});
});
Expand All @@ -146,33 +146,34 @@ describe('/POST Requests route', () => {
.send({
origin: 'Lagos ',
destination: ' London ',
type: 'one-way',
type: 'return',
departureDate: '2019-10-11',
returnDate: '2019-11-11',
reason: ' dgfgfg hfhfhf kfkfkf ',
accommodation: ' bbbv '
})
.end((err, res) => {
expect(res).to.have.status(201);
expect(res.body).to.be.an('object');
expect(res.body.data).to.have.property('origin');
expect(res.body.data).to.have.property('departureDate');
expect(res.body.data).to.have.property('returnDate');
expect(res.body).to.have.property('message')
.eql('travel request booked successfully');
done(err);
});
});

it('should return an error if a requester already has a trip booked for that period', done => {
const departureDate = '2019-10-11';
chai
.request(app)
.post('/api/v1/requests')
.set('authorization', `Bearer ${userToken}`)
.send({
origin: 'Lagos ',
destination: ' London ',
type: 'one-way',
departureDate,
type: 'return',
departureDate: '2019-10-11',
returnDate: '2019-11-11',
reason: ' dgfgfg hfhfhf kfkfkf ',
accommodation: ' bbbv '
})
Expand Down
26 changes: 18 additions & 8 deletions src/utils/Helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ export default class Helper {
*/
static formatRequest(request) {
const {
origin, destination, reason, accommodation, type
origin, destination, reason, accommodation, type, returnDate
} = request;
if (!returnDate) request.returnDate = undefined;
request.origin = origin.trim();
request.destination = destination.trim();
request.type = type.trim();
Expand All @@ -123,12 +124,13 @@ export default class Helper {
* @method noReturn
* @param {object} depart - Departure date from the database
* @param {object} travel - Departure date in the request body
* @param {object} back - Return date in the request body
* @returns {object} JSON response
* @memberof Helper
*/
static noReturn(depart, travel) {
static noReturn(depart, travel, back) {
const conflicts = [];
if (depart === travel) {
if (depart === travel || back === travel) {
conflicts.push(depart);
}
return conflicts;
Expand All @@ -139,13 +141,20 @@ export default class Helper {
* @param {object} travel - Departure date in the request body
* @param {object} depart - Departure date from the database
* @param {object} ret - Return date from the database
* @param {object} back - Return date in the request body
* @returns {object} JSON response
* @memberof Helper
*/
static withReturn(travel, depart, ret) {
static withReturn(travel, depart, ret, back) {
const conflicts = [];
ret = ret.toISOString();
if (travel >= depart && travel <= ret) conflicts.push(depart);
const firstConflict = travel >= depart && travel <= ret;
const secondConflict = back >= depart && back <= ret;
const thirdConflict = depart > travel && depart < back;
const fourthConflict = ret > travel && ret < back;
const firstSecondConflict = firstConflict || secondConflict;
const thirdFourthConflict = thirdConflict || fourthConflict;
if (firstSecondConflict || thirdFourthConflict) conflicts.push(depart);
return conflicts;
}

Expand All @@ -154,17 +163,18 @@ export default class Helper {
* @description Check for trip conflicts
* @param {object} myRequests - Array of user's request
* @param {object} travelDate - Departure date in the request body
* @param {object} backDate - Return date in the request body
* @returns {object} JSON response
* @memberof Helper
*/
static checkTrip(myRequests, travelDate) {
static checkTrip(myRequests, travelDate, backDate = undefined) {
let conflicts;
myRequests.forEach(request => {
let { departureDate } = request;
const { returnDate } = request;
departureDate = departureDate.toISOString();
if (!returnDate) conflicts = Helper.noReturn(departureDate, travelDate);
else conflicts = Helper.withReturn(travelDate, departureDate, returnDate);
if (!returnDate) conflicts = Helper.noReturn(departureDate, travelDate, backDate);
else conflicts = Helper.withReturn(travelDate, departureDate, returnDate, backDate);
});
if (conflicts) return conflicts;
return null;
Expand Down
14 changes: 11 additions & 3 deletions src/utils/validationSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const password = Joi.string().required().regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(

const required = Joi.string().trim().required();
const str = Joi.string().allow('');
const date = Joi.date().iso();

export default {
signup: Joi.object().keys({
Expand All @@ -34,10 +35,17 @@ export default {
request: Joi.object().keys({
origin: required.label('origin is required'),
destination: required.label('destination is required'),
type: required.valid('one-way')
.label('type is required and can only be "one-way"'),
departureDate: Joi.date().iso().required()
type: required.valid('one-way', 'return')
.label('type is required and can either be "one-way" or "return"'),
departureDate: date.required()
.label('departureDate is required and must follow this format: YYYY-MM-DD'),
returnDate: date.when('type', {
is: 'return', then: date.min(Joi.ref('departureDate')).required()
})
.concat(date.when('type', { is: 'one-way', then: date.allow('') }))
.label('returnDate is required for a "return" trip,'
+ ' it cannot come before departureDate'
+ ' and must follow this format: YYYY-MM-DD'),
reason: str.label('reason must be a string'),
accommodation: str.label('accommodation must be a string')
})
Expand Down