diff --git a/.env b/.env index a2b0e71..6fe4e9d 100644 --- a/.env +++ b/.env @@ -1,2 +1,6 @@ -MongoDB_URL = "mongodb+srv://chatapp:4qXzEAQv4Q7i17HO@cluster0.0uitnr9.mongodb.net/?retryWrites=true&w=majority" +MongoDB_URL = "mongodb+srv://usk3210:Z4yljANhOWHwbl6q@cluster0.mmcwbvx.mongodb.net/?retryWrites=true&w=majority" Port = 8080 +secret = "c#$%&HKKM4573$%*jk" + + + diff --git a/Routes/chatRoutes.js b/Routes/chatRoutes.js new file mode 100644 index 0000000..52f3777 --- /dev/null +++ b/Routes/chatRoutes.js @@ -0,0 +1,14 @@ +const Router = require("express").Router() +const { accessChat, createGroupChat, fetchChats, renameGroup, addToGroup, removeFromGroup} = require("../controllers/chatController") +const { protectRoute } = require("../middlewares/authmiddleware") + + +Router.post("/",protectRoute, accessChat) +Router.get("/",protectRoute, fetchChats) +Router.post("/group",protectRoute, createGroupChat) +Router.put("/rename",protectRoute, renameGroup) +Router.put("/groupadd",protectRoute, addToGroup) +Router.put("/groupremove",protectRoute, removeFromGroup) + + +module.exports = Router \ No newline at end of file diff --git a/Routes/userRoutes.js b/Routes/userRoutes.js index fb920a4..3da97ac 100644 --- a/Routes/userRoutes.js +++ b/Routes/userRoutes.js @@ -1,8 +1,43 @@ const express = require("express") const router = express.Router() +const { registerUser,loginUser,getAllusers } = require("../controllers/usercontroller") + +const { body, validationResult } = require('express-validator'); +const { protectRoute } = require("../middlewares/authmiddleware"); + + + + +router.post("/register", + //email must be email + body("email").isEmail(), + // is name is alhabetical + body("name").isAlphanumeric(), + //password length is minimum 5 + body("password").isLength({min:5}),(req,res,next)=>{ + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + next() + } + ,registerUser) + +router.post("/login",body("email").isEmail(), + (req,res,next)=>{ + const errors = validationResult(req); + if(!errors.isEmpty()){ + return res.status(400).json({errors:errors.array()}) + } + next() + } ,loginUser) + +//get all users + +router.get("/",protectRoute, getAllusers) + + -router.post("/login") -router.post("/register") module.exports = router \ No newline at end of file diff --git a/controllers/chatController.js b/controllers/chatController.js new file mode 100644 index 0000000..aa03a02 --- /dev/null +++ b/controllers/chatController.js @@ -0,0 +1,224 @@ + +const Chat = require("../models/chatmodel") + +const accessChat = async(req,res)=>{ + const {userId} = req.body +try{ + if(!userId){ + return res.status(400).json({ + status:"Failed", + error:"userId param not sent with requst" + }) + } + //check chat exists with these userId + let isChat = await Chat.find({ + isgroupchat:false, + users:{$all:[req.user._id,userId]} + + + }).populate("users", "-password").populate("latestMessage") + let chatdata; + console.log(isChat) + if(isChat.length>0){ + return res.status(200).json({ + isChat + }) + } + else{ + chatdata = { + chatName :"sender", + isgroupchat:false, + users:[req.user._id,userId] + } + } + console.log(chatdata) + const createdChat = await Chat.create(chatdata) + const Fullchat = await Chat.find({_id:createdChat._id}).populate("users", "-password") + + return res.status(200).json({ + Fullchat + }) + + + + +} +catch(err){ + return res.status(500).json({ + status:"Failed", + error:err.message + }) + + + +} + +} + +const fetchChats = async(req,res)=>{ + + try{ + + const chats = await Chat.find({users:{$all:[req.user._id]}}) + .populate("users", "-password") + .populate("isgroupAdmin", "-password") + .populate("latestMessage") + .sort({updatedAt : -1}) + return res.json({ + status:"success", + chats:chats + }) + + + } + catch(err){ + return res.json({ + status:"Failed", + error:err.message + }) + } + + +} + +const createGroupChat = async(req,res) =>{ + const {users, name} = req.body + + + //here we take bunch of users and name of groupchat from body + try{ + if(!req.body.users || !req.body.name){ + return res.status(400).json({ + status:"Failed", + error:"Please fill all the fields" + }) + } + //users coming through request is in json format so we parse it for actual array + let users = JSON.parse(req.body.users) + if(users.length>2){ + return res.json({ + status:"Failed", + error:"more than 2users are required to form a group" + }) + } + // we push current loggedin user in to users + users.push(req.user) + + // create groupchat + const groupChat = await Chat.create({ + chatName: req.body.name, + users:users, + isgroupchat:true, + isgroupAdmin: req.user // logged in user is the admin of group + }) + + const fullGroupChat = await Chat.findOne({_id:groupChat.id}) + .populate("users", "-password") + .populate("isgroupAdmin", "-password") + + res.status(200).json({ + status:"success", + fullGroupChat:fullGroupChat + }) + + } + + catch(err){ + return res.status(500).json({ + status:"Failed", + error:err.message + }) + + } + +} + +const renameGroup = async(req,res)=>{ + try{ + const {chatId,chatname} = req.body + + if(!chatId || !chatname){ + return res.status(400).json({error:"all fields are mandatory"}) + } + + const updatedChat = await Chat.findByIdAndUpdate(chatId, + {chatName:chatname },{new:true}) + .populate("users", "-password") + .populate('isgroupAdmin', "-password") + if(!updatedChat){ + return res.status(404).json({ + status:"Failed", + error:"Chat Not Found" + }) + } + else{ + return res.status(200).json({ + status:"success", + updatedChat:updatedChat + }) + } + + } + catch(err){ + return res.status(500).json({ + status:"Failed", + error:err.message + }) + } +} + +const addToGroup = async(req,res)=>{ + try{ + const {chatId, userId} = req.body + const added = await Chat.findByIdAndUpdate(chatId, + { $push:{users:userId}}, + {new:true}).populate("users", "-password") + .populate('isgroupAdmin', "-password") + + if(!added){ + return res.status(400).json({error:"chat was not found"}) + } + return res.json({ + status:"success", + added:added + }) + } + catch(err){ + res.status(500).json({ + status:"Failed", + error:err.message + }) + } +} + + +const removeFromGroup = async(req,res)=>{ + const {chatId, userId} = req.body + + try{ + const removed = await Chat.findByIdAndUpdate(chatId, + {$pull:{users:userId}},{ + new:true + }).populate("users", "-password") + .populate("isgroupAdmin", "-password") + + if(!removed){ + return res.status(400).json({error:"chat was not found with that id"}) + } + return res.json({ + status:"success", + removed:removed + }) + + + } + catch(err){ + res.status(500).json({ + status:"Failed", + error:err.message + }) +} +} + + +module.exports = {accessChat, createGroupChat,fetchChats, renameGroup, addToGroup, removeFromGroup} \ No newline at end of file diff --git a/controllers/usercontroller.js b/controllers/usercontroller.js index 268cf4a..a1b06c7 100644 --- a/controllers/usercontroller.js +++ b/controllers/usercontroller.js @@ -1,8 +1,153 @@ - export const registerUser = async() =>{ +const mongoose = require("mongoose") +const bcrypt = require("bcrypt") +const jwt = require("jsonwebtoken") +const secret = process.env.secret +const User = require("../models/userModel") + + + +const registerUser = async (req, res) => { + + //1. check wheather the user is already existed or not //2.if user is new user then create it //3.if user is already existed then send message like that user already existed - + const { name, password, email } = req.body + + try { + if (!name || !password || !email) { + return res.status(400).json({ + status: "one or more fields are empty", + + }) + } + const existedUser = await User.findOne({ email }) + if (existedUser) { + return res.status(400).json({ + error: "user is already existed" + }) + + } + + // encryping the users password before saving + bcrypt.hash(password, 10, async (err, hash) => { + if (err) { + return res.status(500).json({ + status: "Failed", + error: err.message + + }) + } + const newuser = await User.create({ + name: name, + email: email, + password: hash + }) + return res.status(201).json({ + status: "Success", + message: "user created successfully", + user: newuser + }) + + }) + } + + catch (e) { + res.json({ + status: "error", + message: e.message + + + }) + } + +} + +const loginUser = async (req, res) => { + + const { email, password } = req.body + + try { + //1. we check wheather user having the account with the given email or not + const existeduser = await User.findOne({ email: email }) + if(!existeduser){ + return res.status(409).json({ + status:"Failed", + message:"There is no account with this email" + + }) + } + //2. if user already there , check the given password + bcrypt.compare(password,existeduser.password, (err,result) =>{ + if(err){ + return res.json({ + status:"Failed", + message:err.message + }) + } + if(result){ // the result is true when both passwords are matched, other wise result is false + const token =jwt.sign({_id:existeduser._id},secret) + return res.status(200).json({ + status:"Successful", + message:"Login success", + token : token + }) + } + else{ + return res.status(401).json({ + status:"Failed", + message:"Invalid Credentials" + }) + } + }) + + + + } + + + catch (err) { + + res.json({ + status:"Failed", + error: err.message + }) + } +} + + +//get all users +const getAllusers = async(req,res)=>{ + console.log(req.search) + + try{ + const username = req.query.search + let user; // getting all users except current user + console.log(req.user._id) + if(username){ + user = await User.find({$and:[ + {$or:[{name:{$regex:username, $options:"i"}},{ + email:{$regex:username, $options:"i"} + } + ]} + ,{_id:{$ne:req.user._id}}]}).select("-password") + } + res.send(user) + + + } + catch(err){ + res.status(500).json({ + status:"Failed", + error:err.message + }) + } + + +} + + + -} \ No newline at end of file +module.exports = { registerUser, loginUser, getAllusers} \ No newline at end of file diff --git a/index.js b/index.js index 71a98bb..6b76876 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,15 @@ const express = require("express") const app = express() -const dotenv = require("dotenv") -const Port = process.env.Port +const dotenv = require("dotenv").config() const mongoose = require("mongoose") const bodyparser = require("body-parser") -dotenv.config() +const router = require("./Routes/userRoutes") +const chatRoutes = require("./Routes/chatRoutes") + + + +app.use(express.json()) -app.use(bodyparser) mongoose.connect(process.env.MongoDB_URL,{ useNewUrlParser:true, @@ -15,8 +18,18 @@ mongoose.connect(process.env.MongoDB_URL,{ .then(()=>console.log("connected to Mongodb")) .catch((err)=>console.log(err)) -app.use("/api/v1/users", userRoute) +app.use("/api/v1/users", router) +app.use("/api/v1/chat", chatRoutes) + + +app.all("*",(req,res)=>{ + res.json({ + message:"wrong endpoint" + }) +}) + + -app.listen(Port, ()=>console.log("server started at 8080")) +app.listen(process.env.port, ()=>console.log(`server started at ${process.env.port}`)) diff --git a/middlewares/authmiddleware.js b/middlewares/authmiddleware.js new file mode 100644 index 0000000..bcc30e1 --- /dev/null +++ b/middlewares/authmiddleware.js @@ -0,0 +1,28 @@ +const jwt = require("jsonwebtoken") +const User = require("../models/userModel") +const secret = process.env.secret + + const protectRoute = async(req,res,next) =>{ + if(req.headers.authorization){ + const token = req.headers.authorization.split("Bearer ")[1] + jwt.verify(token,secret,async(err,decode)=>{ + if(err){ + return res.status(400).json({ + status:"Failed", + error:err.message + }) + } + req.user = await User.findOne({_id:decode._id}).select("-password") + next() + + }) + } + else{ + res.status(400).json({ + status:"Failed", + error:"token was Not Found" + }) + } +} + +module.exports = {protectRoute} diff --git a/models/chatmodel.js b/models/chatmodel.js index 8804086..7b44820 100644 --- a/models/chatmodel.js +++ b/models/chatmodel.js @@ -16,11 +16,11 @@ const chatSchema = mongoose.Schema({ ref: "User" }], latestMessage:{ - type:mongoose.ObjectId.Schema.Types.ObjectId, + type:mongoose.Schema.Types.ObjectId, ref:"Message" }, isgroupAdmin:{ - type:mongoose.ObjectId.Schema.Types.ObjectId, + type:mongoose.Schema.Types.ObjectId, ref:"User" } diff --git a/package.json b/package.json index b8b9d56..f35ff91 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,19 @@ "main": "index.js", "scripts": { "start": "node index.js", + "dev": "nodemon index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { + "bcrypt": "^5.1.0", "body-parser": "^1.20.2", "dotenv": "^16.0.3", "express": "^4.18.2", - "mongoose": "^7.1.1" + "express-validator": "^7.0.1", + "jsonwebtoken": "^9.0.0", + "mongoose": "^7.1.1", + "nodemon": "^2.0.22" } }