Skip to content

Commit

Permalink
feature(notification): create notification for new travel request
Browse files Browse the repository at this point in the history
[Finishes #167727317]
  • Loading branch information
orley12 committed Sep 16, 2019
1 parent c9771f9 commit 4ac463a
Show file tree
Hide file tree
Showing 23 changed files with 9,510 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ GOOGLE_CALLBACK=callback uri after google authentication
FACEBOOK_APP_SECRET=facebook client secret
FACEBOOK_APP_ID=facebook client id
FACEBOOK_CALLBACK=callback uri after facebook authentication
CLIENT_URL=frontend host url
CLIENT_URL=frontend host url
9,076 changes: 9,076 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const {
FACEBOOK_APP_SECRET,
FACEBOOK_APP_ID,
FACEBOOK_CALLBACK,
CLIENT_URL
CLIENT_URL,

} = process.env;

Expand Down
35 changes: 26 additions & 9 deletions src/controllers/notificationController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { markNotificationAsRead } from '../services/notificationServices';
import { markNotificationAsRead, getAllNotifications } from '../services/notificationServices';
import { respondWithSuccess, respondWithWarning } from '../helpers/responseHandler';
import statusCode from '../helpers/statusCode';
import Model from '../models';
import responseMessages from '../helpers/responseMessages';

const { Notification } = Model;

Expand All @@ -14,23 +15,39 @@ const { Notification } = Model;
* @returns {object} response object
*/

export const markAllNotifications = async (req, res ) => {
const notifications = req.notifications;
return Promise
export const markAllNotifications = async (req, res ) => {
const { notifications } = req;

return Promise
.all(notifications.map(notification => {
return Notification
.update({
status: true
}, {
where: { userId : notification.userId },
where: { userId: notification.userId },
returning: true,
});
}))
.then(() => {
return respondWithSuccess(res, 200, 'Notifications successfully marked as read');
return respondWithSuccess(res, 200, 'Notifications successfully marked as read');
})
.catch(() => {
return respondWithWarning(res, statusCode.internalServerError, 'Server Error');
return respondWithWarning(res, statusCode.internalServerError, 'Server Error');
});
}
};

export const getAllUserNotification = async (req, res) => {
// de-structure id out of req.auth, then rename id to userId
const { id: userId } = req.auth;

try {
const notifications = await getAllNotifications(userId);
if (!notifications.length) {
return respondWithSuccess(res, statusCode.success, 'You dont have any notifications for now');
}

return respondWithSuccess(res, statusCode.success, responseMessages.success, notifications);
} catch (error) {
return respondWithWarning(res, statusCode.internalServerError, 'Unable to retrieve notifications');
}
};
60 changes: 43 additions & 17 deletions src/controllers/tripController.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,40 @@
import { create } from 'domain';
import request from 'superagent';
import {
postTrip, updateTripStatus, getRequesterEmail, bulkCreate,
getTripRequests, findOneTripRequest, rejectRequest, searchTripRequest,
fetchUserTripStats, fetchTripStats, fetchTripRequests
} from '../services/tripServices';
import { getAllManager } from '../services/userServices';
import { respondWithSuccess, respondWithWarning } from '../helpers/responseHandler';
import statusCode from '../helpers/statusCode';
import { approvedEmitter } from '../helpers/notificationHandler';

import { approvedEmitter, tripRequestEmitter } from '../helpers/notificationHandler';
import { createMessages, createNotificationMessage } from '../helpers/tripRequestMails';

/**
* make trip request
* @param {object} req
* @param {object} res
* @returns {object} json response
* @param {Function} next
* @returns {null} null
*/
export const oneWayTripRequest = async (req, res) => {
const { id } = req.auth;
const { auth: { id }, userProfile: { basicInfo } } = req;
const payload = {
...req.body, status: 'pending', type: 'one-way', userId: id
};
try {
const tripRequest = await postTrip(payload);

return respondWithSuccess(
res,
statusCode.created,
'request successfully sent',
tripRequest.toJSON()
);
const { 0: { users: managers } } = await getAllManager();

const { dataValues: userData } = basicInfo;
createMessages(userData, managers, tripRequest);

const notificationData = createNotificationMessage(tripRequest, managers);
tripRequestEmitter(notificationData);

return respondWithSuccess(res, statusCode.created, 'request successfully sent', tripRequest.toJSON());
} catch (error) {
return respondWithWarning(res, statusCode.internalServerError, 'Internal Server Error');
}
Expand All @@ -38,11 +45,12 @@ export const oneWayTripRequest = async (req, res) => {
* make multi-city trip request
* @param {object} req
* @param {object} res
* @returns {object} json response
* @param {Function} next
* @returns {null} null
*/
export const multiCityTripRequest = async (req, res) => {
let tripRequest;
const { id } = req.auth;
const { auth: { id }, userProfile: { basicInfo } } = req;
const { destination } = req.destination;
const {
origin, destinationId, reason, departureDate, type, subRequest
Expand All @@ -66,6 +74,14 @@ export const multiCityTripRequest = async (req, res) => {
const subRequestedTrips = await bulkCreate(multiCityRequests);
tripRequest = { ...multiCityTrip.toJSON(), destination, subRequestedTrips };

const { 0: { users: managers } } = await getAllManager();

const { dataValues: userData } = basicInfo;
createMessages(userData, managers, tripRequest);

const notificationData = createNotificationMessage(tripRequest, managers);
tripRequestEmitter(notificationData);

return respondWithSuccess(res, statusCode.created, 'request successfully sent', tripRequest);
} catch (error) {
return respondWithWarning(res, statusCode.internalServerError, error.stack);
Expand Down Expand Up @@ -104,10 +120,11 @@ export const approveTripRequest = async (req, res) => {
* A function to create a return trip
* @param {object} req
* @param {object} res
* @returns {object} response
* @param {Function} next
* @returns {null} null
*/
export const returnTripRequest = async (req, res) => {
const { id } = req.auth;
export const returnTripRequest = async (req, res, next) => {
const { auth: { id }, userProfile: { basicInfo } } = req;
const { returnDate, departureDate } = req.body;
const returnDateToISO = new Date(returnDate).toISOString();
const departureDateToISO = new Date(departureDate).toISOString();
Expand All @@ -119,8 +136,17 @@ export const returnTripRequest = async (req, res) => {
...req.body, status: 'pending', type: 'return', userId: id
};
try {
const returnTrip = await postTrip(data);
return respondWithSuccess(res, statusCode.created, 'Request Successful', returnTrip.dataValues);
const tripRequest = await postTrip(data);

const { 0: { users: managers } } = await getAllManager();

const { dataValues: userData } = basicInfo;
createMessages(userData, managers, tripRequest);

const notificationData = createNotificationMessage(tripRequest, managers);
tripRequestEmitter(notificationData);

return respondWithSuccess(res, statusCode.created, 'request successfully sent', tripRequest.toJSON());
} catch (error) {
return respondWithWarning(res, statusCode.internalServerError, 'Internal Server Error');
}
Expand Down
54 changes: 54 additions & 0 deletions src/docs/swagger/definitions/successResponse.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,61 @@ const noContent = {
}
};

const NotificationResponds = {
type: 'object',
properties: {
success: {
type: 'boolean'
},
message: {
type: 'string'
},
payload: {
type: 'object',
properties: {
id: {
type: 'integer',
format: 'int32',
example: 1
},
type: {
type: 'string',
example: 'Approved Trip'
},
title: {
type: 'string',
example: 'Trade Fair'
},
message: {
type: 'string',
example: 'Your Trip has been approved'
},
tripId: {
type: 'integer',
example: 1,
},
commentId: {
type: 'integer',
example: 2
},
userId: {
type: 'integer',
example: 4
},
createdAt: {
type: 'string',
format: 'date-time'
},
updatedAt: {
type: 'string',
format: 'date-time'
}
}
}
}
};
export {
NotificationResponds,
created,
noContent,
success
Expand Down
49 changes: 48 additions & 1 deletion src/docs/swagger/paths/notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,52 @@ export const markAllNotficationPath = {
}
}
}
},
};

export const getAllNotficationPath = {
get: {
tags: [
'notifications'
],
security: [
{
BearerToken: []
}
],
summary: 'Get all user notificatons',
description: 'Allows signed-in user to all there notificatons',
responses: {
200: {
description: 'User gets all notifications successfully',
schema: {
$ref: '#/definitions/NotificationResponds'
}
},
400: {
description: 'Invalid request details',
schema: {
$ref: '#/definitions/badRequest'
}
},
401: {
description: 'Unauthorized user',
schema: {
$ref: '#/definitions/notAuthorized'
}
},
404: {
description: 'Unauthorized user',
schema: {
$ref: '#/definitions/notFound'
}
},
500: {
description: 'Server error',
schema: {
$ref: '#/definitions/serverError'
}
}
}
};
},
};
6 changes: 4 additions & 2 deletions src/docs/swagger/swagger.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// eslint-disable-next-line import/named
import { created, success } from './definitions/successResponse';
import { created, success, NotificationResponds } from './definitions/successResponse';
import {
badRequest, notAuthorized, accessForbidden, notFound, conflict,
serverError
Expand Down Expand Up @@ -51,7 +51,7 @@ import profilePath from './paths/profile';
import { createComment } from './definitions/createComment';
import { createCommentPath, deleteCommentPath, getTripCommentsPath } from './paths/commentPath';
import { postChatPath, getChatsPath } from './paths/chat';
import { markAllNotficationPath } from './paths/notification';
import { markAllNotficationPath, getAllNotficationPath } from './paths/notification';
import { createChat } from './definitions/chat';
import { flightPath } from './paths/flight';
import { FlightCreate } from './definitions/flight';
Expand Down Expand Up @@ -164,6 +164,7 @@ const swaggerDocument = {
'/bookings': bookingPath,
'/bookings/{bookingId}': getSingleBookingPath,
'/notifications/readAll': markAllNotficationPath,
'/notifications': getAllNotficationPath,
'/chat': postChatPath,
'/chats/?sender={sender}&recipient={recipient}': getChatsPath,
'/flights/add/{tripId}': flightPath
Expand All @@ -187,6 +188,7 @@ const swaggerDocument = {
createUser, // create user
verifyUser, // verify user
success, // 200
NotificationResponds,
created,
ProfileHeaders, // profile header token
ProfileCreate, // profile create request
Expand Down
28 changes: 27 additions & 1 deletion src/helpers/notificationHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const tripEmitter = new EventEmitter();
/**
* @exports approvedEmitter
* @exports approveTripNotification
* @exports tripRequestEmitter
*/


Expand Down Expand Up @@ -85,11 +86,37 @@ export const chatEmitter = (data) => {

/**
* Function to listen for the created chat event and send
* Function to emit trip request
* @param {object} data
* @returns {null} null
*/
export const tripRequestEmitter = (data) => {
tripEmitter.emit('trip request', data);
};

/**
* Function to listen for the trip request event and send
* a notification to the all managers for approval
* @param {Object} io
* @param {Object} staffs
* @override
*/
export const tripRequestNotification = (io, staffs) => {
tripEmitter.on('trip request', async (payload) => {
const notification = await createNotification(payload);
payload.managersEmail.forEach(email => {
io.to(staffs[email]).emit('trip request', notification);
});
});
};

/**
* Function to listen for the trip request event and send
* a notification to both requester and manager for approprate action.
* @param {Object} io
* @param {Object} staffs
* @override
*/
export const chatBot = (io, staffs) => {
tripEmitter.on('chat', (payload) => {
const receivers = [payload.sender, payload.recipient];
Expand All @@ -114,7 +141,6 @@ export const getChatsEmitter = (data) => {
* @param {Object} staffs
* @override
*/

export const getPrivateChats = (io, staffs) => {
tripEmitter.on('chats', (payload) => {
const receivers = [payload.sender, payload.recipient];
Expand Down
1 change: 1 addition & 0 deletions src/helpers/responseMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export default {
expiredSession: 'Please signin to continue',
profileCreated: 'Profile successfully created',
profileUpdated: 'Profile updated',
success: 'success',
};
Loading

0 comments on commit 4ac463a

Please sign in to comment.