Skip to content

Commit

Permalink
ft(booking and travel notifications):add a userId column in the accom…
Browse files Browse the repository at this point in the history
…modation table

refactor the existing notification code to ensure reusability
Add notification functionality to the trip and booking controller.
[Starts #169258639]
  • Loading branch information
hezzie committed Dec 12, 2019
1 parent e8f915a commit 739d3f7
Show file tree
Hide file tree
Showing 29 changed files with 632 additions and 157 deletions.
3 changes: 3 additions & 0 deletions src/controllers/BookingController.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Response from '../helpers/Response';
import AccommodationService from '../services/BookingService';
import NotificationService from '../services/NotificationService';

/**
* @exports
Expand All @@ -18,6 +19,8 @@ class BookingController {
static async bookAccommodation(req, res) {
try {
const result = await AccommodationService.createAccommodationService(req);
req.result = result;
await NotificationService.newBookingNotification(req);
return Response.successMessage(req, res, 'You have booked an accommodation facility successfully', result, 201);
} catch (error) {
return Response.errorMessage(req, res, 'Server error', 500);
Expand Down
35 changes: 35 additions & 0 deletions src/controllers/NotificationController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

import dotenv from 'dotenv';
import Response from '../helpers/Response';
import NotificationService from '../services/NotificationService';

const { markNotificationAsRead } = NotificationService;
dotenv.config();
/**
* @exports
* @class AccommodationController
*/
class AccommodationController {
/**
* Travel Admin can be able to create accommodation facility
* @static
* @param {object} req request object
* @param {object} res response object
* @memberof AccommodationController
* @returns {object} data
*/
static async markNotificationsAsRead(req, res) {
try {
const { notificationIds } = req.body;
const notificationArr = req.params.notificationId
? notificationIds.filter(id => id === parseInt(req.params.notificationId, 10))
: notificationIds;
await markNotificationAsRead(notificationArr);
return Response.successMessage(req, res, 'Notification marked as read successfully', '', 201);
} catch (err) {
return Response.errorMessage(req, res, 'Server Error', 500);
}
}
}

export default AccommodationController;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.describeTable('accommodations').then(tableDefinition => {
if (!tableDefinition['userId']){
return queryInterface.addColumn('accommodations', 'userId', {
type: Sequelize.INTEGER,
allowNull: true,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
references: {
model: 'users',
key: 'id'
} } );
} else {
return Promise.resolve(true);
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('accommodations');
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.describeTable('notifications').then(tableDefinition => {
if (!tableDefinition['bookingId']){
return queryInterface.addColumn('notifications', 'bookingId', {
type: Sequelize.INTEGER,
allowNull: true,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
references: {
model: 'bookings',
key: 'id'
} } );
} else {
return Promise.resolve(true);
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('notifications');
}
}


5 changes: 5 additions & 0 deletions src/database/models/accommodations.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module.exports = (sequelize, DataTypes) => {
const accommodations = sequelize.define('accommodations', {
name: DataTypes.STRING,
userId: DataTypes.INTEGER,
cityId: DataTypes.INTEGER,
address: DataTypes.STRING,
description: DataTypes.STRING,
Expand All @@ -26,6 +27,10 @@ module.exports = (sequelize, DataTypes) => {
sourceKey: "cityId",
targetKey: "id",
});
accommodations.belongsTo(models.users, {
sourceKey: "userId",
targetKey: "id",
});
accommodations.hasMany(models.ratings, {
targetKey: "accommodationId",
sourceKey: "id",
Expand Down
6 changes: 6 additions & 0 deletions src/database/models/notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module.exports = (sequelize, DataTypes) => {
const notifications = sequelize.define('notifications', {
userId: DataTypes.INTEGER,
bookingId:DataTypes.INTEGER,
managerId: DataTypes.INTEGER,
tripRequestId: DataTypes.INTEGER,
message: DataTypes.TEXT,
Expand All @@ -18,6 +19,11 @@ module.exports = (sequelize, DataTypes) => {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
notifications.belongsTo(models.booking, {
sourceKey:'bookingId',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
});
};
return notifications;
};
9 changes: 8 additions & 1 deletion src/database/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,17 @@ module.exports = (sequelize, DataTypes) => {
{onUpdate: 'cascade'}
);
users.hasMany(models.notifications,
{targetKey: 'id'},
{sourceKey: 'id'},
{targetKey: 'userId'},
{onDelete: 'cascade'},
{onUpdate: 'cascade'}
);
users.hasMany(models.accommodations,
{sourceKey:'id'},
{targetKey: 'userId'},
{onDelete: 'cascade'},
{onUpdate: 'cascade'}
);
};
return users;
};
33 changes: 33 additions & 0 deletions src/database/seeders/20191105144530-accommodations.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
address: 'kigali',
description: '5 stars hotels...',
googleCoordinates: '-1.956173, 30.063451',

createdAt: new Date(),
updatedAt: new Date()
},
Expand All @@ -18,6 +19,7 @@ module.exports = {
address: 'kigali',
description: '6 stars hotels...',
googleCoordinates: '-1.953656, 30.062354',

createdAt: new Date(),
updatedAt: new Date()
},
Expand All @@ -27,9 +29,40 @@ module.exports = {
address: 'kigali',
description: '7 stars hotels...',
googleCoordinates: '-1.953656, 30.062354',

createdAt: new Date(),
updatedAt: new Date()
},
{
name: 'Golden keys hotel',
description: 'Best place to be',
cityId: 1,
googleCoordinates: 'yeaaaahaaa',

address: 'qwerty',
createdAt: new Date(),
updatedAt: new Date()
},
{
name: 'radisson blue hotel',
description: 'Best place to rest',
cityId: 3,
googleCoordinates: 'yeaaaahaaasdddds',

address: 'qwertysssds',
createdAt: new Date(),
updatedAt: new Date()
},
{
name: 'Akagera safe motel',
cityId: 2,
address: 'Kigali',
description: 'Pool',
googleCoordinates: '111.45, 456.34',

createdAt: new Date(),
updatedAt: new Date()
}

], {});
},
Expand Down
30 changes: 0 additions & 30 deletions src/database/seeders/20191203191136-accommodation.js

This file was deleted.

23 changes: 0 additions & 23 deletions src/database/seeders/20191203204612-accommodations.js

This file was deleted.

5 changes: 4 additions & 1 deletion src/helpers/TripHelper.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Response from './Response';
import emailHelper from './EmailHelper';
import { tripRequests, trips } from '../database/models';

import NotificationService from '../services/NotificationService';

/**
* @export
Expand Down Expand Up @@ -34,6 +34,9 @@ class TripHelper {
returnDate: item.returnDate
});
});

req.result = newTrip;
await NotificationService.newTripRequestNotification(req);
emailHelper.approveEmailHelper(req, process.env.MANAGER_EMAIL);
return Response.successMessage(req, res, 'Trip requested successfully', newTrip, 201);
} catch (err) {
Expand Down
18 changes: 18 additions & 0 deletions src/helpers/notificationConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import eventEmitters from './eventEmitters';

const notificationEvents = (eventName, clientData) => {
eventEmitters.emit(eventName, JSON.stringify(clientData));
};

const sendNotification = (io, emitterEvent, socketEvent) => {
io.on('connection', (socket) => {
eventEmitters.on(emitterEvent, (data) => {
socket.emit(socketEvent, data);
});
});
};

export {
notificationEvents,
sendNotification
};
11 changes: 5 additions & 6 deletions src/helpers/socketIo.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import socketIO from 'socket.io';
import eventEmitters from './eventEmitters';
import { sendNotification } from './notificationConfig';

const socketIo = (server) => {
const io = socketIO(server);
Expand All @@ -12,11 +12,10 @@ const socketIo = (server) => {
}
});

io.on('connection', (socket) => {
eventEmitters.on('notification_message', (data) => {
socket.emit('approve_reject', data);
});
});
sendNotification(io, 'approve_reject_notification', 'approve_reject_client');
sendNotification(io, 'booking_notification', 'booking_client');
sendNotification(io, 'trip_request_notification', 'trip_request_client');

return io;
};

Expand Down
13 changes: 13 additions & 0 deletions src/middlewares/Validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,5 +281,18 @@ class Validate {
check('rooms.*.roomType', 'roomType should be a minimum of 2 letters').isString().isLength({ min: 2 })
];
}

/**
* Validate notification id
* @static
* @returns {object} errors
*/
static validateNotificationIdRules() {
return [
check('notificationId', 'The notificationId should be an integer').isInt().optional(),
check('notificationIds', 'The notificationIds should be an array').isArray(),
check('notificationIds.*', 'The notification IDs should be integer').isInt()
];
}
}
export default Validate;
6 changes: 5 additions & 1 deletion src/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io('http://localhost:3000');
socket.on('approve_reject', (name) => {
const rr = ['approve_reject_client','booking_client','trip_request_client'];
rr.forEach((ev)=>{
socket.on(ev, (name) => {
console.log(JSON.parse(name));
});
})

</script>
</html>
3 changes: 3 additions & 0 deletions src/routes/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import locationRoute from './locationRoute';
import commentRoute from './commentRoute';
import accommodationRoute from './accommodationRoute';
import bookingRouter from './bookingRoute';
import notificationRoute from './notificationRoute';


const router = Router();
router.use('/auth', authRoute);
Expand All @@ -19,6 +21,7 @@ router.use('/location', locationRoute);
router.use('/users', userRoute);
router.use('/accommodations', accommodationRoute);
router.use('/trips', bookingRouter);
router.use('/notifications', notificationRoute);


export default router;
Loading

0 comments on commit 739d3f7

Please sign in to comment.