diff --git a/public/index.html b/public/index.html index 0cf2d17..468eb3f 100644 --- a/public/index.html +++ b/public/index.html @@ -151,7 +151,7 @@ @@ -163,10 +163,14 @@

Eagles E-commerce Chat Room

+
+ +
+
- +
@@ -182,8 +186,13 @@

Eagles E-commerce Chat Room

const chatRoomSection = document.getElementById("chatRoom"); const verifyToken = document.getElementById("TokenVerfication"); const verifyTokenForm = document.getElementById("verifyToken"); - - const url = "https://eagles-ec-be-development.onrender.com/api/v1/users/login"; + const port = window.location.port + + + const isProduction = window.location.hostname === "https://eagles-ec-be-development.onrender.com" + const url = isProduction ? "https://eagles-ec-be-development.onrender.com/api/v1/users/login":`http://localhost:${port}/api/v1/users/login`; + const twoFactorAuthUrl = isProduction? "https://eagles-ec-be-development.onrender.com/api/v1/users/2fa-verify": `http://localhost:${port}/api/v1/users/2fa-verify` + const loginUser = async (email, password) => { try { const response = await fetch(url, { @@ -197,13 +206,17 @@

Eagles E-commerce Chat Room

throw new Error("Login failed"); } const data = await response.json(); - localStorage.setItem("loginToken", JSON.stringify(data.token)); - const decodedToken = JSON.parse(atob(token.split(".")[1])); - if(decodedToken.otp){ + + if (data.status === "Pending"){ + localStorage.setItem("Token-otp_Verify", JSON.stringify(data.token)); showTokenVerfication(); - }else{ - showChatRoom(); } + if(data.status === 200){ + localStorage.setItem("loginToken", JSON.stringify(data.token)); + showChatRoom(); + } + + } catch (error) { console.error(error.message); } @@ -213,15 +226,38 @@

Eagles E-commerce Chat Room

e.preventDefault(); const email = document.getElementById("email").value; const password = document.getElementById("password").value; - await loginUser(email, password); + const response = await loginUser(email, password); + const data = await response.json(); localStorage.setItem("loginToken", JSON.stringify(data.token)); }); verifyTokenForm.addEventListener("submit", async(e) =>{ e.preventDefault(); - const verifyToken = document.getElementById("tokenVer").value; - localStorage.setItem("loginToken", JSON.stringify(verifyToken)); + const otp = parseInt(document.getElementById("tokenVer").value); + + let pre_token = localStorage.getItem("Token-otp_Verify") + pre_token = pre_token.replace(/"/g, ''); + // fixing verification token to the url params + const url = new URL(twoFactorAuthUrl) + const params = new URLSearchParams(); + params.append("token", pre_token); + url.search = params.toString(); + const adjustedUrl = url.toString() + + + const response = await fetch(adjustedUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ otp, pre_token }), + }) + + const data = await response.json(); + + localStorage.setItem("loginToken", JSON.stringify(data.token)); + verifyToken.style.display = "none"; showChatRoom(); }) @@ -244,13 +280,14 @@

Eagles E-commerce Chat Room

const active = document.getElementById("active-list"); const token = localStorage.getItem("loginToken"); const decodedToken = JSON.parse(atob(token.split(".")[1])); + let userId; if (token) { try { const { id, name } = decodedToken; userNameInput.value = name; userId = id; - console.log(decodedToken); + } catch (error) { console.error("Error parsing token:", error.message); } @@ -304,5 +341,13 @@

Eagles E-commerce Chat Room

+ + + + diff --git a/public/private.html b/public/private.html new file mode 100644 index 0000000..3a238be --- /dev/null +++ b/public/private.html @@ -0,0 +1,286 @@ + + + + + + + + Eagles Private Chat + + + +
+ + + + +
+

Chat with Our Sellers

+
+ + + +
+ +
+ + +
+
+
+ + + + \ No newline at end of file diff --git a/src/config/socketCofing.ts b/src/config/socketCofing.ts index ca02cc8..94b9fc1 100644 --- a/src/config/socketCofing.ts +++ b/src/config/socketCofing.ts @@ -1,5 +1,6 @@ import { Server,Socket } from "socket.io"; import { sendMessages, getPastMessages } from "../controllers/chatsController"; +import { createAPrivateMessageSocket, retrieveAUserToUserPrivateMessageSocket } from "../controllers/privateChatController"; @@ -9,7 +10,7 @@ import { sendMessages, getPastMessages } from "../controllers/chatsController"; connectedClients.add(socket.id); io.emit('connected client', connectedClients.size); - console.log("connected client") + console.log(`connected client`) await getPastMessages(socket); @@ -21,6 +22,13 @@ import { sendMessages, getPastMessages } from "../controllers/chatsController"; socket.on('chat message', async(data: any) => { await sendMessages(io, data); }); + socket.on('private chat message', async(data: any) =>{ + await createAPrivateMessageSocket(socket, data); + } ) + socket.on('past private messages between two users', async(data:any) =>{ + + await retrieveAUserToUserPrivateMessageSocket(socket, data) + }) }); } diff --git a/src/controllers/chatsController.ts b/src/controllers/chatsController.ts index c951b8c..bbaef83 100644 --- a/src/controllers/chatsController.ts +++ b/src/controllers/chatsController.ts @@ -9,7 +9,7 @@ export const sendMessages = async(io:Server,data:any) =>{ const newMessage = { sender, userId, - message + message, } const validated:any = chatMessageSchema.validate(newMessage); if(validated.error){ @@ -30,5 +30,4 @@ export const getPastMessages = async(socket:Socket) =>{ } export const joiRoom = async(req:Request,res:Response) => { res.sendFile(path.resolve('public/index.html')) -} - +} \ No newline at end of file diff --git a/src/controllers/privateChatController.ts b/src/controllers/privateChatController.ts new file mode 100644 index 0000000..854089f --- /dev/null +++ b/src/controllers/privateChatController.ts @@ -0,0 +1,121 @@ +import * as PrivateChatService from '../services/privateChat.service'; +import { Socket, Server } from 'socket.io'; +import { Request, Response, NextFunction } from 'express'; +import { PrivateMessageSchema, UserToUserPrivateMessageSchema } from '../schemas/privateMessageSchema'; +import path from 'path'; + +export const createAPrivateMessageController = async(req: Request, res: Response, next: NextFunction) => { + try { + // @ts-ignore + const userId = req.user.id; + // @ts-ignore + const sender = req.user.username; + const message = req.body.message; + const messageArgs = { + userId: userId, + receiverId: parseInt(req.params.id), + message: message, + sender + + }; + + const validated:any = PrivateMessageSchema.validate(messageArgs); + + if (!validated){ + res.status(400).json({message: validated.error.message}); + } + + const newMessage = await PrivateChatService.CreatePrivateMessage(messageArgs); + + if(!newMessage){ + res.status(400).json({message: "Error while creating your message"}); + } + res.status(201).json(newMessage); + next(); + } + catch (error) { + res.status(400).json({message: `${error}`}); + } +}; + +export const createAPrivateMessageSocket= async(socket: Socket, data:any) =>{ + if (!data.message || data.message.trim() === '') { + socket.emit('validation error', { message: 'Empty message found' }); + return; + } + const message= { + userId: data.userId, + sender: data.sender, + receiverId: data.receiverId, + message: data.message + } + + const validated: any = PrivateMessageSchema.validate(message) + + if (!validated){ + socket.emit('validation error', { message: validated.error.message }); + } + else{ + const sentPrivateMessage = await PrivateChatService.CreatePrivateMessage(message) + socket.emit('private message sent', sentPrivateMessage ) + + } + +} + +// getting all private chats a sender have with other users (those where He might be a receiver or a sender) + +export const getAllPrivateChatsController = async(req: Request, res: Response, next: NextFunction) => { + try{ + const userId = (req as any).user.id; + const userChats = await PrivateChatService.getAllUserPrivateChats(userId); + if(!userChats){ + res.status(400).json({message: "Error while fetching your chats"}); + } + res.status(200).json(userChats); + next(); + } + catch(error){ + + res.status(400).json({message: "Error while fetching your chats"}); + } + } + + +// getting all Private Messages between two user ( a sender and an other user) +export const getUserToUserPrivateMessagesController = async(req: Request, res: Response, next: NextFunction) => { + try{ + // @ts-ignore + const userId = req.user.id; + const receiverId = parseInt(req.params.id); + + const validated:any = UserToUserPrivateMessageSchema.validate([userId, receiverId]); + const userMessages = await PrivateChatService.getUserToUserPrivateMessages(userId, receiverId); + if(!userMessages){ + res.status(400).json({message: "Error while fetching your messages"}); + } + res.status(200).json(userMessages); + next(); + } + catch(error){ + res.status(400).json({message: `${error}`}); + } +}; + +export const retrieveAUserToUserPrivateMessageSocket = async(socket:Socket, data:any) =>{ + const receiverId = data.receiverId; + const userId = data.userId; + + const validated:any = UserToUserPrivateMessageSchema.validate({userId, receiverId}); + if (!validated){ + socket.emit('validation error', { message: validated.error.message }); + } + else{ + const userMessages = await PrivateChatService.getUserToUserPrivateMessages(userId, receiverId); + socket.emit('past private user to user message sent', userMessages ) + } +} + +export const privateChat = async(req:Request,res:Response) => { + res.sendFile(path.resolve('public/private.html')) +} \ No newline at end of file diff --git a/src/controllers/userControllers.ts b/src/controllers/userControllers.ts index 5597377..578b84b 100644 --- a/src/controllers/userControllers.ts +++ b/src/controllers/userControllers.ts @@ -17,6 +17,7 @@ import { env } from "../utils/env"; import { Emailschema, resetPasswordSchema } from "../schemas/resetPasswordSchema"; import { clearExpiredUserData } from "../jobs/isPasswordExpired"; import { use } from "passport"; +import { fetchAllsellersService } from "../services/wishlist.service"; export const fetchAllUsers = async (req: Request, res: Response) => { @@ -432,4 +433,19 @@ export const verifyUserController = async (req: Request, res: Response): Promise } catch (error) { res.status(500).json({ error: 'Failed to verify new user.' }); } -}; \ No newline at end of file +}; +export const fetchAllsellers= async (req: Request, res: Response) =>{ + const sellers = await fetchAllsellersService(); + if (sellers){ + res.status(200).json( + { + data: sellers + } + ); + } + else{ + res.status(400).json({ + message: "No sellers found" + }) + } +} diff --git a/src/docs/privateChatDoc.ts b/src/docs/privateChatDoc.ts new file mode 100644 index 0000000..980df6b --- /dev/null +++ b/src/docs/privateChatDoc.ts @@ -0,0 +1,109 @@ +export const PrivateChatSchema = { + properties: { + type: "object", + sender: { + type: "string", + required: true, + }, + receiverId: { + type: "number", + required: true, + }, + message: { + type: "string", + required: true, + }, + + }, + +} + +export const createPrivateChat={ + tags: ['PrivateChat'], + security: [{bearerAuth: []}], + summary: 'Create a Private Chat or continue messagingin an existing Private Chat', + parameters: [ + { + name: 'id', + in: 'path', + required: true, + description: 'receiver Id', + schema: { + type: "number" + }, + } + ], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + message:{ + type: 'string', + }, + } + }, + }, + }, + }, + + responses: { + 201: { + description: 'created', + }, + 403: { + description: 'Forbidden', + }, + 404: { + description: 'Not found', + }, + }, +}; + +export const getAllUserPrivateChats={ + tags: ['PrivateChat'], + security: [{bearerAuth: []}], + summary: 'Get all Private Chats for a User', + responses: { + 200: { + description: 'Success', + }, + 403: { + description: 'Forbidden', + }, + 404: { + description: 'Not found', + }, + }, +}; + + +export const getUserToUserPrivateMessages = { + tags: ['PrivateChat'], + security: [{bearerAuth: []}], + summary: 'Get all Private Messages between two users', + parameters: [ + { + name: 'id', + in: 'path', + required: true, + description: 'receiver Id', + schema: { + type: 'number' + }, + } + ], + responses: { + 200: { + description: 'Success', + }, + 403: { + description: 'Forbidden', + }, + 404: { + description: 'Not found', + }, + }, +}; diff --git a/src/docs/swagger.ts b/src/docs/swagger.ts index 11fb92d..a6d2b27 100644 --- a/src/docs/swagger.ts +++ b/src/docs/swagger.ts @@ -46,6 +46,7 @@ import { homepage } from "./home"; import { payment } from "./payments"; import { createReviewProduct, deleteReview, getReviewProduct, reviewSchema, updateReviewProduct } from "./reviews"; import { getAdProducts } from "./products"; +import {PrivateChatSchema, getAllUserPrivateChats, getUserToUserPrivateMessages, createPrivateChat } from "./privateChatDoc" const docRouter = express.Router(); @@ -82,6 +83,7 @@ const options = { { name: "Wishes", description: "Endpoints related to Wishes" }, { name: "Carts", description: "Endpoints related to Cart"}, { name: "Payments", description: "Endpoints related to payments" }, + {name: "PrivateChat", description: "Endpoints related to Private Chat"}, ], paths: { @@ -194,6 +196,13 @@ const options = { patch: updateReviewProduct, delete: deleteReview }, + "/api/v1/chats/private": { + get: getAllUserPrivateChats, + }, + "/api/v1/chats/private/{id}": { + post: createPrivateChat, + get: getUserToUserPrivateMessages, + }, }, components: { schemas: { @@ -205,7 +214,8 @@ const options = { Product: productSchema, Category: categorySchema, Wish: wishSchema, - Review: reviewSchema + Review: reviewSchema, + PrivateChat: PrivateChatSchema }, securitySchemes: { bearerAuth: { diff --git a/src/routes/chatRoutes.ts b/src/routes/chatRoutes.ts index a79c3a5..4fb9943 100644 --- a/src/routes/chatRoutes.ts +++ b/src/routes/chatRoutes.ts @@ -1,4 +1,5 @@ import { Router } from "express"; import { joiRoom } from "../controllers/chatsController"; export const joinChatRoomRoutes = Router(); -joinChatRoomRoutes.get('/',joiRoom); \ No newline at end of file +joinChatRoomRoutes.get('/',joiRoom); +joinChatRoomRoutes.post('/', ) \ No newline at end of file diff --git a/src/routes/index.ts b/src/routes/index.ts index 092dfd9..138224d 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -7,8 +7,10 @@ import { joinChatRoomRoutes } from "./chatRoutes"; import cartRoutes from "./cartRoutes"; import notificationRoutes from "./notificationRoutes"; import paymentRouter from "./paymentRoutes"; +import PrivateChatRoutes from "./privateChatRoutes"; const appROutes = Router(); +appROutes.use("/chats", PrivateChatRoutes); appROutes.use("/users", userRoutes); appROutes.use("/products", productsRouter); appROutes.use("/categories", categoriesRouter); diff --git a/src/routes/privateChatRoutes.ts b/src/routes/privateChatRoutes.ts new file mode 100644 index 0000000..fdc9b0b --- /dev/null +++ b/src/routes/privateChatRoutes.ts @@ -0,0 +1,16 @@ +import { + createAPrivateMessageController, + getAllPrivateChatsController, + getUserToUserPrivateMessagesController, privateChat } from "../controllers/privateChatController"; +import { isLoggedIn } from "../middlewares/isLoggedIn"; + +import express from "express"; + + const PrivateChatRoutes = express.Router(); + +PrivateChatRoutes.post('/private/:id',isLoggedIn, createAPrivateMessageController); +PrivateChatRoutes.get('/private', isLoggedIn, getAllPrivateChatsController); +PrivateChatRoutes.get('/private/:id',isLoggedIn, getUserToUserPrivateMessagesController); +PrivateChatRoutes.get('/page', privateChat); + +export default PrivateChatRoutes; \ No newline at end of file diff --git a/src/routes/userRoutes.ts b/src/routes/userRoutes.ts index d78da1d..a6efdbe 100644 --- a/src/routes/userRoutes.ts +++ b/src/routes/userRoutes.ts @@ -1,5 +1,5 @@ import { Router } from "express"; -import { fetchAllUsers, createUserController, userLogin, updatePassword, tokenVerification, handleSuccess, handleFailure,updateProfileController, getProfileController, otpVerification,updateUserRole, changeUserAccountStatus, logout, sendResetLinkEmail, resetPasswordController, verifyUserEmailController, verifyUserController } from "../controllers/userControllers"; +import { fetchAllUsers, createUserController, userLogin, updatePassword, tokenVerification, handleSuccess, handleFailure,updateProfileController, getProfileController, otpVerification,updateUserRole, changeUserAccountStatus, logout, sendResetLinkEmail, resetPasswordController, verifyUserEmailController, verifyUserController, fetchAllsellers } from "../controllers/userControllers"; import { emailValidation, validateSchema } from "../middlewares/validator"; import { isLoggedIn } from "../middlewares/isLoggedIn"; import { passwordUpdateSchema } from "../schemas/passwordUpdate"; @@ -24,6 +24,10 @@ userRoutes.put("/passwordupdate", isLoggedIn, validateSchema(passwordUpdateSchem userRoutes.post("/login", emailValidation,validateSchema(logInSchema),isDisabled,isVerified,userLogin); userRoutes.post("/register", emailValidation, validateSchema(signUpSchema), createUserController); userRoutes.put("/passwordupdate", isLoggedIn, validateSchema(passwordUpdateSchema), updatePassword); +userRoutes.get("/sellers", fetchAllsellers) +userRoutes.put("/passwordupdate", isLoggedIn,validateSchema(passwordUpdateSchema), updatePassword) +userRoutes.post("/login", emailValidation,validateSchema(logInSchema),isDisabled,userLogin); +userRoutes.post("/register", emailValidation,validateSchema(signUpSchema), createUserController); userRoutes.get("/2fa-verify/:token",tokenVerification); userRoutes.post("/2fa-verify",otpVerification); userRoutes.get('/profile', diff --git a/src/schemas/messageSchema.ts b/src/schemas/messageSchema.ts index 136159c..17a9c9d 100644 --- a/src/schemas/messageSchema.ts +++ b/src/schemas/messageSchema.ts @@ -9,4 +9,4 @@ export const chatMessageSchema = Joi.object({ message:Joi.string() .min(1) .required(), -}) \ No newline at end of file +}).options({allowUnknown:false}) \ No newline at end of file diff --git a/src/schemas/privateMessageSchema.ts b/src/schemas/privateMessageSchema.ts new file mode 100644 index 0000000..7a2ab82 --- /dev/null +++ b/src/schemas/privateMessageSchema.ts @@ -0,0 +1,15 @@ +import Joi from "joi"; + +export const PrivateMessageSchema= Joi.object({ + + receiverId: Joi.number() + .required(), + message:Joi.string() + .min(1) + .required(), +}).options({allowUnknown:false}) + +export const UserToUserPrivateMessageSchema = Joi.object({ + receiverId: Joi.number() + .required(), +}).options({allowUnknown:false}) \ No newline at end of file diff --git a/src/sequelize/migrations/20240529192329-add-private-Chat-Model.js b/src/sequelize/migrations/20240529192329-add-private-Chat-Model.js new file mode 100644 index 0000000..affdab1 --- /dev/null +++ b/src/sequelize/migrations/20240529192329-add-private-Chat-Model.js @@ -0,0 +1,65 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up (queryInterface, Sequelize) { + await queryInterface.createTable('PrivateChats', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'users', + key: 'id' + } + }, + receiverId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'users', + key: 'id' + } + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + + // await queryInterface.addColumn('messages', 'privateChatId', { + // type: Sequelize.INTEGER, + // allowNull: true, + // references: { + // model: 'PrivateChats', + // key: 'id' + // }, + // onUpdate: 'CASCADE', + // onDelete: 'SET NULL', + // }); + // await queryInterface.addColumn('messages', 'isPrivate',{ + // type: Sequelize.BOOLEAN, + // allowNull: false + // }) + + + + }, + + + async down (queryInterface, Sequelize) { + await queryInterface.dropTable('PrivateChats'); + // await queryInterface.removeColumn('messages', 'privateChatId'); + // await queryInterface.removeColumn('messages', 'isPrivate') + + } +}; diff --git a/src/sequelize/models/messages.ts b/src/sequelize/models/messages.ts index 8a68481..52e0164 100644 --- a/src/sequelize/models/messages.ts +++ b/src/sequelize/models/messages.ts @@ -1,11 +1,14 @@ import { Model,DataTypes } from "sequelize"; import sequelize from "../../config/dbConnection"; import User from "./users"; +import PrivateChat from "./privateChats"; export interface MessagesAttributes{ id?:number, sender:string, userId:number, + isPrivate?: boolean + privateChatId?:number, message:string, createdAt?:Date, updatedAt?:Date @@ -15,6 +18,8 @@ class Message extends Model implements MessagesAttributes{ id?:number; sender!:string; userId!: number; + privateChatId!: number | undefined; + isPrivate!: boolean; message!:string; createdAt?: Date | undefined; updatedAt?: Date | undefined; @@ -38,6 +43,18 @@ Message.init({ key:"id" } }, + isPrivate:{ + type: DataTypes.BOOLEAN, + allowNull: false, + }, + privateChatId:{ + type:DataTypes.INTEGER, + allowNull: true, + references:{ + model:"PrivateChats", + key:"id" + } + }, message:{ type: DataTypes.STRING, allowNull: false, @@ -52,4 +69,10 @@ User.hasMany(Message,{ Message.belongsTo(User,{ foreignKey: 'userId' }) +PrivateChat.hasMany(Message,{ + foreignKey: 'privateChatId' +}) +Message.belongsTo(PrivateChat,{ + foreignKey: 'privateChatId' +}) export default Message; \ No newline at end of file diff --git a/src/sequelize/models/privateChats.ts b/src/sequelize/models/privateChats.ts new file mode 100644 index 0000000..379f4ee --- /dev/null +++ b/src/sequelize/models/privateChats.ts @@ -0,0 +1,72 @@ +import sequelize from "../../config/dbConnection"; +import { Model,DataTypes } from "sequelize"; +import User from "./users"; +import Message from "./messages"; + +export interface PrivateChatAttributes{ + id?:number, + userId:number, + receiverId:number, + createdAt?:Date, + updatedAt?:Date +} + +class PrivateChat extends Model implements PrivateChatAttributes{ + id?:number; + userId!:number; + receiverId!:number; + createdAt?:Date; + updatedAt?:Date; +} + + +PrivateChat.init({ + id:{ + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: DataTypes.INTEGER, + }, + userId:{ + type:DataTypes.INTEGER, + allowNull: false, + references:{ + model:"User", + key:"id" + } + }, + receiverId:{ + type:DataTypes.INTEGER, + allowNull: false, + references:{ + model:"User", + key:"id" + } + }, + createdAt:{ + allowNull: false, + type:DataTypes.DATE + }, + updatedAt:{ + allowNull: false, + type:DataTypes.DATE + } +},{ + sequelize, + modelName:"PrivateChats" +}); + +User.hasMany(PrivateChat,{ + foreignKey: 'userId' +}) +PrivateChat.belongsTo(User,{ + foreignKey: 'userId' +}) +User.hasMany(PrivateChat,{ + foreignKey: 'receiverId' +}) +PrivateChat.belongsTo(User,{ + foreignKey: 'receiverId' +}) + +export default PrivateChat; \ No newline at end of file diff --git a/src/services/chatServices.ts b/src/services/chatServices.ts index 3705d29..bb9987a 100644 --- a/src/services/chatServices.ts +++ b/src/services/chatServices.ts @@ -1,8 +1,17 @@ import Message from "../sequelize/models/messages"; + export const newChatMessages = async(message:any) => { try { - const newMessage = await Message.create(message); + const chat = { + sender: message.sender, + userId: message.userId, + message: message.message, + isPrivate: false, + privateChatId: undefined + } + + const newMessage = await Message.create(chat); if(!newMessage){ return false; }else{ @@ -15,7 +24,7 @@ export const newChatMessages = async(message:any) => { export const pastMessages = async() =>{ try { - const currentMessages = await Message.findAll(); + const currentMessages = await Message.findAll({where: {isPrivate: false}}); if(!currentMessages){ return false; }else{ @@ -24,4 +33,4 @@ export const pastMessages = async() =>{ } catch (error:any) { throw new Error(error.message); }; -}; +}; \ No newline at end of file diff --git a/src/services/privateChat.service.ts b/src/services/privateChat.service.ts new file mode 100644 index 0000000..bc93250 --- /dev/null +++ b/src/services/privateChat.service.ts @@ -0,0 +1,92 @@ +import User from "../sequelize/models/users"; +import PrivateChat from "../sequelize/models/privateChats"; +import Message from "../sequelize/models/messages"; +import { findUserById } from "./user.service"; +import {Op} from "sequelize"; + +export const createPrivateChat = async (userId: number, receiverId: number) => { + try { + + const [chat, created] = await PrivateChat.findOrCreate({ + where: { + [Op.or]: + [ + {userId: userId, receiverId: receiverId}, + {userId: receiverId, receiverId: userId} + ] + }, + defaults: {userId, receiverId} + }) + + let privateChatId = chat.id; + + return privateChatId; + } + catch (error) { + throw new Error(`Error while Creating your Private Chat: ${error}`); + } +}; + +export const CreatePrivateMessage = async(message:any) => { + try{ + + const reciever = await findUserById(message.receiverId.toString()); + if (!reciever){ + throw new Error("Receiver not found"); + } + if (message.message.length < 1){ + throw new Error("Empty message found!") + } + const privateChatId = await createPrivateChat(message.userId, message.receiverId); + + const newMessage = await Message.create({...message, privateChatId, isPrivate: true}); + return newMessage; + + } + catch(error){ + throw new Error(`Error while Creating your Private Message: ${error}`); + } +}; + +export const getAllUserPrivateChats = async(userId: number) => { + try{ + const userChats = await PrivateChat.findAll({ + where: { + [Op.or]: [ + {userId: userId}, + {receiverId: userId} + ]}, + include: [ + { + model: Message, + as: "messages" + }] + } + ); + return userChats + } + catch(error){ + throw new Error(`Error while Fetching your Chats: ${error}`); + } +}; + +export const getUserToUserPrivateMessages = async (userId: number, receiverId: number) =>{ + try{ + const reciever = await findUserById(receiverId.toString()); + if (!reciever || reciever === null || reciever === undefined){ + throw new Error("Receiver not found"); + } + const privateChat = await PrivateChat.findOne({where :{userId, receiverId}}); + if (privateChat){ + const PrivateMessages = await Message.findAll({where:{privateChatId: privateChat.id}}) + + return PrivateMessages; + } + else{ + return []; + } + } + catch (error){ + throw new Error(`Error while Fetching your Messages: ${error}`) + } +} diff --git a/src/services/wishlist.service.ts b/src/services/wishlist.service.ts index 5ed0bc3..00058bc 100644 --- a/src/services/wishlist.service.ts +++ b/src/services/wishlist.service.ts @@ -62,3 +62,9 @@ export const removeProduct = async (userId: number, productId: number) => { return removeProduct } + +export const fetchAllsellersService = async() =>{ + const sellers = await User.findAll({where: {roleId: 2}}); + + return sellers; +} diff --git a/src/utils/server.ts b/src/utils/server.ts index 77bd2ba..22a33c0 100644 --- a/src/utils/server.ts +++ b/src/utils/server.ts @@ -45,7 +45,6 @@ export const io: SocketIOServer = new SocketIOServer(server, { export const notificationEmitter = new NotificationEmitter(io); const eventHandler = new EventHandler(io, notificationEmitter); - app.use(express.json()); app.use(express.urlencoded({ extended: true }));