From 64de86009275e9bc7016f6761f4d692ae198242d Mon Sep 17 00:00:00 2001 From: Keagan Aromin Date: Thu, 9 Jan 2025 16:58:53 -0800 Subject: [PATCH] Send message endpoint (message.routes.js AND message.controller.js) AND protectRoutes.js middleware --- backend/controllers/message.controller.js | 44 +++++++++++++++++++++++ backend/middleware/protectRoute.js | 39 ++++++++++++++++++++ backend/routes/message.routes.js | 10 ++++++ backend/routes/user.routes.js | 0 backend/server.js | 7 +++- 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 backend/controllers/message.controller.js create mode 100644 backend/middleware/protectRoute.js create mode 100644 backend/routes/message.routes.js create mode 100644 backend/routes/user.routes.js diff --git a/backend/controllers/message.controller.js b/backend/controllers/message.controller.js new file mode 100644 index 0000000..5e6a3bd --- /dev/null +++ b/backend/controllers/message.controller.js @@ -0,0 +1,44 @@ +import Conversation from "../models/conversation.model.js"; +import Message from "../models/message.model.js"; +import { getReceiverSocketId, io } from "../socket/socket.js"; + +export const sendMessage = async (req, res) => { + try { + const { message } = req.body; + const { id: receiverId } = req.params; + const senderId = req.user._id; + + let conversation = await Conversation.findOne({ + participants: { $all: [senderId, receiverId] }, + }); + + if (!conversation) { + conversation = await Conversation.create({ + participants: [senderId, receiverId], + }); + } + + const newMessage = new Message({ + senderId, + receiverId, + message, + }); + + if (newMessage) { + conversation.messages.push(newMessage._id); + } + + // SOCKET IO FUNCTIONALITY WILL GO HERE + + // await conversation.save(); + // await newMessage.save(); + + // this will run in parallel + await Promise.all([conversation.save(), newMessage.save()]); + + res.status(201).json(newMessage); + } catch (error) { + console.log("Error in sendMessage controller: ", error.message); + res.status(500).json({ error: "Internal server error" }); + } +}; \ No newline at end of file diff --git a/backend/middleware/protectRoute.js b/backend/middleware/protectRoute.js new file mode 100644 index 0000000..e806467 --- /dev/null +++ b/backend/middleware/protectRoute.js @@ -0,0 +1,39 @@ +import jwt from 'jsonwebtoken'; +import User from "../models/user.model.js"; + +const protectRoute = async (req, res, next) => { + try { + const token = req.cookies.jwt; + //case where there is no token in the request + if (!token) { + return res.status(401).json({error: "Unauthorized - No Token Provided"}) //return http 401 error (unauthorized) + } + + //remember, when we generate tokens in utils/generateToken.js, we sign using JWT_SECRET - the .env file will be in the server/backend upon deployment + //so the server can use the secret, which is in the .env file, to verify/decode the token from the client + const decoded = jwt.verify(token, process.env.JWT_SECRET); + + //case where the verification fails + if (!decoded) { + return res.status(401).json({error: "Unauthorized - Invalid Token"}) //return http 401 error (unauthorized) + } + + //assign the .userId attribute of the decoded message to user + const user = await User.findById(decoded.userId); + + if (!user) { + return res.status(404).json({ error: "User not found" }); + } + + //assign request user attribute to the user we decoded using mongoose model + jwt + req.user = user; + + //this says that once everything has run, exit this function and call the next one + next(); + } catch (error) { + console.log("Error in protectRoute middleware: ", error.message); + res.status(500).json({error: "Internal server error"}); + } +} + +export default protectRoute; \ No newline at end of file diff --git a/backend/routes/message.routes.js b/backend/routes/message.routes.js new file mode 100644 index 0000000..633f694 --- /dev/null +++ b/backend/routes/message.routes.js @@ -0,0 +1,10 @@ +import express, { Router } from "express"; +import { sendMessage } from "../controllers/message.controller"; +import protectRoute from "../middleware/protectRoute"; + +const router = express.Router(); + +//when we have a post request, we first run protectRoute until the next() call is reached, then we run sendMessage +router.post("/send/:id", protectRoute, sendMessage) + +export default router; \ No newline at end of file diff --git a/backend/routes/user.routes.js b/backend/routes/user.routes.js new file mode 100644 index 0000000..e69de29 diff --git a/backend/server.js b/backend/server.js index cc3ada3..9a8c6eb 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,7 +1,9 @@ import express from "express"; import dotenv from "dotenv"; - +import cookieParser from "cookie-parser"; import authRoutes from "./routes/auth.routes.js"; +import messageRoutes from "./routes/auth.routes.js"; +import userRoutes from "./routes/auth.routes.js"; import connectToMongoDB from "./db/connectToMongoDB.js"; const app = express(); @@ -10,8 +12,11 @@ const PORT = process.env.PORT || 5000; dotenv.config(); app.use(express.json()); // to parse the incoming requests with JSON payloads (from req.body) +app.use(cookieParser()); //before running routes call the middleware so we can access cookies (see protectRoute.js) app.use("/api/auth", authRoutes); +app.use("/api/messages", messageRoutes); +app.use("/api/users", userRoutes); // app.get("/", (req, res) => { // // root route http://localhost:5000/