Skip to content

Commit

Permalink
Merge pull request #55 from atlp-rwanda/187354274-fit-notifications
Browse files Browse the repository at this point in the history
Creating notifications
  • Loading branch information
niyontwali authored May 10, 2024
2 parents e345866 + cfa5afb commit 92a721f
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 1 deletion.
45 changes: 45 additions & 0 deletions src/controllers/notificationsController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Request, Response } from 'express';
import Notification from '../database/models/notification';
import { sendInternalErrorResponse } from '../validations';
import logger from '../logs/config';

export const getNotifications = async (req: Request, res: Response): Promise<void> => {
try {
const { userId } = req.params;
const notifications = await Notification.findAll({ where: { userId } });
if (notifications.length === 0) {
logger.error('No notifications were found');
res.status(404).json({
ok: false,
message: 'No notifications that were found',
});
return;
}
res.status(200).json({ ok: true, data: notifications });
} catch (error) {
logger.error(error);
sendInternalErrorResponse(res, error);
return;
}
};

export const markNotificationAsRead = async (req: Request, res: Response): Promise<void> => {
const { id } = req.params;
const { isRead } = req.body;
try {
const notification = await Notification.findByPk(id);
if (!notification) {
res.status(401).json({
ok: false,
errorMessage: 'No such notification that were found! Try again',
});
return;
}
notification.isRead = isRead;
await notification.save();
res.status(200).json({ ok: true, message: 'Notification were updated successfully' });
} catch (error) {
logger.error(error);
sendInternalErrorResponse(res, error);
}
};
17 changes: 17 additions & 0 deletions src/controllers/productsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { Product, ProductAttributes } from '../database/models/Product';
import { Size, SizeAttributes } from '../database/models/Size';
import logger from '../logs/config';
import sequelize from '../database/models';
import Notification from '../database/models/notification';
import User from '../database/models/user';
import { sendEmail } from '../helpers/send-email';

export const createProduct = async (req: Request, res: Response) => {
try {
Expand Down Expand Up @@ -254,3 +257,17 @@ export const deleteProductById = async (req: Request, res: Response) => {
sendInternalErrorResponse(res, error);
}
};
//HOOKS TO MANAGE NOTIFICATIONS AFTER OPERATIONS ARE MADE ON PRODUCT

Product.afterCreate(async product => {
const notification = await Notification.create({
message: `Product called: ${product.name} was created successfully!`,
isRead: false,
userId: product.sellerId,
});
const user = await User.findOne({ where: { id: product.sellerId }, attributes: ['email', 'firstName', 'lastName'] });
if (!user) {
return Promise.reject(new Error("User cannot be found! So the email won't be send successfully"));
}
sendEmail('added_product_notification', { email: user.email, name: user.firstName });
});
46 changes: 46 additions & 0 deletions src/database/migrations/20240507222727-create-notification.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';

const { UUIDV4 } = require('sequelize');

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Notifications', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
},
message: {
type: Sequelize.STRING,
allowNull: false,
},
isRead: {
type: Sequelize.BOOLEAN,
allowNull: false,
},
userId: {
type: Sequelize.UUID,
allowNull: false,
references: {
model: 'Users',
key: 'id',
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Notifications');
},
};
55 changes: 55 additions & 0 deletions src/database/models/notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Model, Optional, DataTypes, UUIDV4 } from 'sequelize';
import sequelize from './index';

export interface NotificationAttributes {
id: string;
userId: string;
message: string;
isRead: boolean;
}

export interface NotificationCreationAttributes extends Optional<NotificationAttributes, 'id'> {}

class Notification extends Model<NotificationAttributes, NotificationCreationAttributes> {
public id!: string;
public message!: string;
public userId!: string;
public isRead!: boolean;
public readonly createdAt: Date | undefined;
public readonly updatedAt: Date | undefined;
}
Notification.init(
{
id: {
type: DataTypes.UUID,
defaultValue: UUIDV4,
primaryKey: true,
allowNull: false,
unique: true,
},
message: {
type: DataTypes.STRING,
allowNull: false,
},
isRead: {
type: DataTypes.BOOLEAN,
allowNull: false,
},
userId: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'Users',
key: 'id',
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
},
},
{
sequelize: sequelize,
timestamps: true,
}
);

export default Notification;
21 changes: 21 additions & 0 deletions src/docs/products.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ paths:
message:
type: string
example: Something went wrong when creating the product
<<<<<<< HEAD

/api/products/{sizeId}/available:
put:
Expand Down Expand Up @@ -308,6 +309,26 @@ paths:
500:
description: Internal server error

=======
/api/notifications/{userId}:
get:
tags:
- Product
summary: Fetching all notifications for product creation
description: This get all notifications that are also related to certain product lifecycle change and also related to the user.
security:
- bearerAuth: []
parameters:
- in: path
name: userId
required: true
type: string
responses:
404:
description: Notifications were not found! Please try again
200:
description: Notifications were successfully fetched
>>>>>>> 8a7df7b (Creating notifications)
components:
securitySchemes:
bearerAuth:
Expand Down
19 changes: 19 additions & 0 deletions src/helpers/send-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,25 @@ export const sendEmail = async (type: string, data: IData) => {
mailOptions.subject = 'Verification code';
mailOptions.html = emailContent;
break;
case 'added_product_notification':
email = {
body: {
name: data.name,
intro: `Your product has been added successfully!`,
action: {
instructions: 'To view your product on platform, Click here:',
button: {
color: '#22BC66',
text: 'View on the platform',
link: 'https://e-commerce-mavericks.com/login',
},
},
outro: 'Thank you for working with us. If you need any help, please free to contact us!',
},
};
mailOptions.subject = 'Product added successfully';
mailOptions.html = mailGenerator.generate(email);
break;
}
const info = await transporter.sendMail(mailOptions);
logger.info('Send Mailer', info);
Expand Down
3 changes: 2 additions & 1 deletion src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import roleRoute from './roleRoute';
import productRouter from './productRoutes';
import { categoryRouter } from './categoryRouter';
import wishlistRoute from './wishlistRoute';

import notificationRoutes from './notificationRoutes';
const router = Router();

router.use('/users', userRoute);
Expand All @@ -18,4 +18,5 @@ router.use('/roles', roleRoute);
router.use('/products', productRouter);
router.use('/category', categoryRouter);
router.use('/wishlist', wishlistRoute);
router.use('/notifications', notificationRoutes);
export default router;
9 changes: 9 additions & 0 deletions src/routes/notificationRoutes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express from 'express';
import { getNotifications, markNotificationAsRead } from '../controllers/notificationsController';

const route = express.Router();

route.get('/:userId', getNotifications);
route.patch('/:id', markNotificationAsRead);

export default route;

0 comments on commit 92a721f

Please sign in to comment.