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

Creating notifications #55

Merged
merged 1 commit into from
May 10, 2024
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
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;
Favor-star marked this conversation as resolved.
Show resolved Hide resolved
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;
Loading