Skip to content

Commit 8312dfa

Browse files
committed
feature(notitfication):user comment notification
Implementation of user comment notification. Users should receive comment notification when comments are created on thier trip request. Finished[167728039]
1 parent 788f084 commit 8312dfa

10 files changed

+224
-88
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@
7474
],
7575
"reporter": [
7676
"lcov",
77-
"text"
77+
"text",
78+
"text-summary"
7879
],
7980
"cache": false,
8081
"require": [

src/controllers/CommentController.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import UserRepository from '../repositories/UserRepository';
22
import CommentRepository from '../repositories/CommentRepository';
33
import TripRequestRepository from '../repositories/TripRequestRepository';
4+
import NotificationRepository from '../repositories/NotificationRepository';
45

56
import { sendSuccessResponse, sendErrorResponse } from '../utils/sendResponse';
67

@@ -35,17 +36,29 @@ class CommentController {
3536
const tripRequestDetails = await TripRequestRepository.findById({ uuid: tripRequestUuid });
3637
if (!tripRequestDetails) return sendErrorResponse(res, 404, 'This trip request does not exist');
3738
const { user_uuid: tripRequestOwner } = tripRequestDetails;
38-
39+
40+
// ensuring ownership
3941
const isAllowed = await checkrequestOwner(tripRequestOwner, userUuid, userRole);
4042
if (!isAllowed && userRole === 'Manager') return sendErrorResponse(res, 403, 'You are not the manager of the user that created this trip request');
4143
if (!isAllowed && userRole !== 'Manager') return sendErrorResponse(res, 403, 'You can\'t comment on a trip request you did not create');
42-
44+
45+
// creating comment
4346
const commentDetails = {
4447
user_uuid: userUuid,
4548
trip_request_uuid: tripRequestUuid,
4649
message
4750
};
51+
52+
// create notification
53+
const notificationDetails = {
54+
user_uuid: userUuid,
55+
message,
56+
status: 'unread',
57+
notification_type: 'comment'
58+
};
59+
4860
const createdComment = await CommentRepository.create(commentDetails);
61+
await NotificationRepository.create(notificationDetails);
4962
return sendSuccessResponse(res, 201, createdComment);
5063
} catch (err) {
5164
return next(err);
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/* eslint-disable */
2+
import Model from '../models';
3+
import { setHeaders, addHook } from '../utils/NotificationHelpers';
4+
import tripRepository from '../repositories/TripRequestRepository';
5+
import NotificationRepository from '../repositories/NotificationRepository';
6+
import dotenv from 'dotenv';
7+
8+
dotenv.config();
9+
10+
const { Comment } = Model;
11+
12+
/**
13+
* @description Comment controller
14+
*/
15+
class CommentNotifications {
16+
/**
17+
* @param {Object} req - HTTP request object
18+
*
19+
* @param {Object} res - HTTP response object
20+
*
21+
* @param {Function} next - Function to trigger next middleware
22+
*
23+
* @return {Object} Return success message and account creation status
24+
*/
25+
26+
constructor() {
27+
this.model = Comment;
28+
}
29+
30+
/**
31+
* @description Add notifications for comment model
32+
*
33+
* @param {Object} req - HTTP request object
34+
*
35+
* @param {Object} res - HTTP response object
36+
*
37+
* @param {Function} next - Function to execute next function
38+
*
39+
* @returns {Void} Nothing is been returned. Just sets hooks to a given model
40+
*/
41+
async create (req, res, next) {
42+
43+
const appURL = process.env['APP_BASE_PATH'] || 'localhost:3000';
44+
let tripsObj = [];
45+
const currentUserUUID = req.userData.uuid;
46+
47+
// Set HTTP headers for SSE
48+
setHeaders(req, res);
49+
50+
try {
51+
// Get all unread notifications
52+
const notifs = await NotificationRepository.getAll({
53+
user_uuid: currentUserUUID,
54+
status: 'unread',
55+
notification_type: 'comment'
56+
});
57+
58+
// Construct comment summary and link to comment.
59+
notifs.reduce((trips, currentTrip)=>{
60+
return tripsObj.push({
61+
uuid: currentTrip.uuid,
62+
message: currentTrip.message,
63+
link: `${appURL}/trips/${currentTrip.uuid}`
64+
})
65+
}, tripsObj);
66+
67+
// Send unread comments to user
68+
res.write('event: comment\n');
69+
res.write(`data: ${JSON.stringify(tripsObj)}\n\n`);
70+
71+
// Method to execute for every comment creation
72+
const helper = async (comment) => {
73+
const {dataValues: {trip_request_uuid}} = comment;
74+
75+
const {
76+
dataValues: {
77+
user_uuid: requester_id,
78+
uuid: trip_uuid
79+
}
80+
} = await tripRepository.findById({uuid: trip_request_uuid});
81+
82+
console.log("inside error zone", requester_id);
83+
if(requester_id == currentUserUUID){
84+
res.write(`event: comment\n`);
85+
res.write(`data: link: https://localhost:3000/trips/${trip_uuid}\n`);
86+
res.write(`data: ${JSON.stringify({
87+
message: comment.message
88+
})}\n\n`);
89+
}
90+
}
91+
92+
// Add realtime notification. Triggered after new comment is created.
93+
addHook(Comment, 'afterCreate', 'notification', helper);
94+
95+
} catch (error) {
96+
next(error);
97+
}
98+
}
99+
}
100+
101+
export default new CommentNotifications();

src/controllers/ExampleUserNotificationController.js

Lines changed: 0 additions & 75 deletions
This file was deleted.

src/database/seeders/20190825080303-create-users.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ export default {
2525
created_at: Sequelize.literal('NOW()'),
2626
updated_at: Sequelize.literal('NOW()')
2727
},
28+
{
29+
uuid: uuid(),
30+
name: 'Wokoro Samuel Douye',
31+
32+
role: 'Requester',
33+
is_verified: true,
34+
password: hashPassword('Samsizzy777'),
35+
created_at: Sequelize.literal('NOW()'),
36+
updated_at: Sequelize.literal('NOW()')
37+
},
2838
{
2939
uuid: uuid(),
3040
name: 'Makaraba Blessing',
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import uuid from 'uuid';
2+
3+
'use strict';
4+
5+
module.exports = {
6+
up: (queryInterface, Sequelize) => {
7+
const notificationData = [
8+
{
9+
uuid: uuid(),
10+
user_uuid: 'abef6009-48be-4b38-80d0-b38c1bc39922',
11+
message: 'Can i have my trip request approved?',
12+
status: 'unread',
13+
notification_type: 'comment',
14+
created_at: new Date(),
15+
updated_at: new Date()
16+
},
17+
{
18+
uuid: uuid(),
19+
user_uuid: 'abef6009-48be-4b38-80d0-b38c1bc39922',
20+
message: 'Please i need my trip request approved',
21+
status: 'unread',
22+
notification_type: 'comment',
23+
created_at: new Date(),
24+
updated_at: new Date()
25+
}
26+
];
27+
return queryInterface.bulkInsert('Notifications', notificationData, {});
28+
},
29+
30+
down: (queryInterface, Sequelize) => {
31+
return queryInterface.bulkDelete('Notifications', null, {});
32+
}
33+
};

src/routes/notifications.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
import { Router } from 'express';
22

3-
import userNotificationController from '../controllers/ExampleUserNotificationController';
3+
import authenticateUser from '../middlewares/authenticateUser'
4+
import commentNotificationController from '../controllers/CommentNotificationController';
45

56
const notificationRoutes = Router();
67

78
// Live notification endpoint for user creation.
8-
notificationRoutes.get('/user', userNotificationController.create);
9-
10-
// Example Live notification endpoint for request.
11-
12-
// notificationRoutes.get(
13-
// '/request',
14-
// authenticateUser,
15-
// notificationController.requestNotifications
16-
// );
9+
notificationRoutes.get('/comment', authenticateUser, commentNotificationController.create);
1710

1811
export default notificationRoutes;

tests/comment.notification.test.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { describe, it } from 'mocha';
2+
import sinon from 'sinon';
3+
import sinonChai from 'sinon-chai';
4+
import chai, { expect } from 'chai';
5+
import chaiHttp from 'chai-http';
6+
import CommentNotificationController from '../src/controllers/CommentNotificationController';
7+
import {req, res, next} from './mock.data';
8+
import NotificationRepository from '../src/repositories/NotificationRepository';
9+
import tripRepository from '../src/repositories/TripRequestRepository';
10+
11+
chai.use(chaiHttp);
12+
chai.use(sinonChai);
13+
14+
describe('Comment notification', () => {
15+
16+
before(()=>{
17+
sinon.spy(res, 'writeHead');
18+
sinon.spy(res, 'write');
19+
});
20+
21+
after(()=>{ sinon.restore(); });
22+
23+
it('it should set headers should be set', ()=>{
24+
CommentNotificationController.create(req, res, next);
25+
expect(res.writeHead).to.be.calledWith(200, {
26+
'Content-Type': 'text/event-stream',
27+
'Cache-Control': 'no-cache',
28+
Connection: 'keep-alive'
29+
});
30+
expect(res.write).to.be.calledWith('\n');
31+
});
32+
33+
it('it should return unread comments', ()=>{
34+
35+
sinon.stub(NotificationRepository, 'getAll').returns([
36+
{
37+
uuid: 'abef6009-48be-4b38-80d0-b38c1bc39922',
38+
user_uuid: 'abef6009-48be-4b38-80d0-b38c1bc39922',
39+
message: 'Please i need my trip request approved',
40+
status: 'unread',
41+
notification_type: 'comment',
42+
created_at: new Date(),
43+
updated_at: new Date()
44+
}
45+
]);
46+
CommentNotificationController.create(req, res, next);
47+
expect(res.write.called).to.be.true;
48+
NotificationRepository.getAll.restore();
49+
});
50+
51+
it('it should call next function for server error', ()=>{
52+
sinon.stub(NotificationRepository, 'getAll').throws();
53+
expect(CommentNotificationController.create).throws
54+
NotificationRepository.getAll.restore();
55+
});
56+
});

tests/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import './office.test';
2222
// Password reset
2323
import './passwordReset.test';
2424

25+
// Comment notification
26+
import './comment.notification.test';
27+
2528
// UTILITIES
2629

2730
// Getting user info test

tests/request.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,5 +398,6 @@ describe('Test Create Trip Request', () => {
398398
expect(next.called).to.true;
399399
sinon.restore();
400400
});
401+
401402
});
402403
});

0 commit comments

Comments
 (0)