-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8e091eb
Showing
49 changed files
with
11,209 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Node.js | ||
node_modules | ||
npm-debug.log | ||
|
||
# Environment Variables | ||
.env | ||
|
||
# Build outputs | ||
dist | ||
build | ||
|
||
# IDE files | ||
.idea | ||
.vscode | ||
|
||
# Logs | ||
logs | ||
*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Chat-App | ||
This is Full stack chat app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { Conversation } from "../model/conversationModel.js"; | ||
import { Message } from "../model/messageModel.js"; | ||
import { getReceiverSocketId,io } from "../socket/socket.js"; | ||
|
||
export const sendMessage = async (req,res) => { | ||
try { | ||
const senderId = req.id; | ||
const receiverId = req.params.id; | ||
const {message} = req.body; | ||
|
||
let gotConversation = await Conversation.findOne({ | ||
participants:{$all : [senderId, receiverId]}, | ||
}); | ||
|
||
if(!gotConversation){ | ||
gotConversation = await Conversation.create({ | ||
participants:[senderId, receiverId] | ||
}) | ||
}; | ||
const newMessage = await Message.create({ | ||
senderId, | ||
receiverId, | ||
message | ||
}); | ||
if(newMessage){ | ||
gotConversation.messages.push(newMessage._id); | ||
}; | ||
|
||
|
||
await Promise.all([gotConversation.save(), newMessage.save()]); | ||
|
||
// SOCKET IO | ||
const receiverSocketId = getReceiverSocketId(receiverId); | ||
if(receiverSocketId){ | ||
io.to(receiverSocketId).emit("newMessage", newMessage); | ||
} | ||
return res.status(201).json({ | ||
newMessage | ||
}) | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
} | ||
export const getMessage = async (req, res) => { | ||
try { | ||
const receiverId = req.params.id; | ||
const senderId = req.id; | ||
|
||
const conversation = await Conversation.findOne({ | ||
participants: { $all: [senderId, receiverId] } | ||
}).populate({ | ||
path: 'messages', | ||
match: { | ||
deletedBy: { $ne: senderId } // Exclude messages deleted by the logged-in user | ||
} | ||
}); | ||
|
||
return res.status(200).json(conversation?.messages); | ||
} catch (error) { | ||
console.log(error); | ||
return res.status(500).json({ success: false, message: "Failed to get messages" }); | ||
} | ||
}; | ||
|
||
|
||
export const deleteMessage = async (req, res) => { | ||
try { | ||
const messageId = req.params.messageId; | ||
const userId = req.id; // The logged-in user | ||
|
||
// Find the message | ||
const message = await Message.findById(messageId); | ||
|
||
if (!message) { | ||
return res.status(404).json({ success: false, message: "Message not found" }); | ||
} | ||
|
||
// Check if the user is either the sender or receiver | ||
if (message.senderId.toString() !== userId && message.receiverId.toString() !== userId) { | ||
return res.status(403).json({ success: false, message: "You cannot delete this message" }); | ||
} | ||
|
||
// Add the user to the deletedBy list (if not already there) | ||
if (!message.deletedBy.includes(userId)) { | ||
message.deletedBy.push(userId); | ||
} | ||
|
||
await message.save(); // Save the updated message with deletedBy field | ||
|
||
return res.status(200).json({ success: true, message: "Message deleted for you" }); | ||
} catch (error) { | ||
console.log(error); | ||
return res.status(500).json({ success: false, message: "Failed to delete message" }); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import { configDotenv } from "dotenv"; | ||
import { User } from "../model/userModel.js"; | ||
import bcrypt from 'bcryptjs' | ||
import jwt from "jsonwebtoken"; | ||
|
||
export const register = async (req, res) => { | ||
try { | ||
const { fullName, username, password, confirmpass, gender } = req.body; | ||
|
||
// Validation | ||
if (!fullName || !username || !password || !gender || !confirmpass) { | ||
return res.status(400).json({ | ||
message: "All Fields are required", | ||
success: false, | ||
}); | ||
} | ||
|
||
if (password !== confirmpass) { | ||
return res.status(400).json({ | ||
message: "Passwords do not match", | ||
success: false, | ||
}); | ||
} | ||
|
||
// Check for existing user | ||
const userExists = await User.findOne({ username }); | ||
if (userExists) { | ||
return res.status(400).json({ | ||
message: "Username already exists, please choose another", | ||
success: false, | ||
}); | ||
} | ||
|
||
// Hash password | ||
const hashedPassword = await bcrypt.hash(password, 10); | ||
|
||
// Profile photo URLs based on gender | ||
const profilePhoto = gender === 'male' | ||
? `https://avatar.iran.liara.run/public/boy?username=${username}` | ||
: `https://avatar.iran.liara.run/public/girl?username=${username}`; | ||
|
||
// Create the user | ||
await User.create({ | ||
fullName, | ||
username, | ||
password: hashedPassword, | ||
profilePhoto, | ||
gender, | ||
}); | ||
|
||
return res.status(201).json({ | ||
message: "Account created successfully", | ||
success: true, | ||
}); | ||
|
||
} catch (error) { | ||
console.error(error); | ||
return res.status(500).json({ | ||
message: "Server error. Please try again later.", | ||
success: false, | ||
}); | ||
} | ||
}; | ||
|
||
|
||
export const login = async(req, res) => { | ||
try { | ||
const { username, password } = req.body; | ||
|
||
// Check for missing fields | ||
if (!username || !password) { | ||
return res.status(400).json({ | ||
message: "All fields are required", | ||
success: false | ||
}); | ||
} | ||
|
||
// Find user in the database | ||
const user = await User.findOne({ username }); | ||
if (!user) { | ||
return res.status(400).json({ | ||
message: "Invalid username or password", | ||
success: false | ||
}); | ||
} | ||
|
||
// Check if password matches | ||
const isMatch = await bcrypt.compare(password, user.password); | ||
if (!isMatch) { | ||
return res.status(400).json({ | ||
message: "Invalid username or password", | ||
success: false | ||
}); | ||
} | ||
|
||
// Generate JWT token | ||
const token = jwt.sign({ userId: user._id }, process.env.TOKEN_SECRET, { expiresIn: "1d" }); | ||
|
||
// Set token in a cookie | ||
res.cookie("token", token, { httpOnly: true, maxAge: 24 * 60 * 60 * 1000 }); // 1 day | ||
|
||
return res.status(200).json({ | ||
message: "Login successful", | ||
success: true, | ||
user: { | ||
_id: user._id, | ||
username: user.username, | ||
fullName: user.fullName, | ||
profilePhoto: user.profilePhoto | ||
} | ||
}); | ||
|
||
} catch (error) { | ||
console.error(error); | ||
return res.status(500).json({ | ||
message: "Server error. Please try again later.", | ||
success: false | ||
}); | ||
} | ||
}; | ||
|
||
export const logout = (req, res) => { | ||
res.cookie("token", "", { maxAge: 0 }); | ||
return res.json({ | ||
message: "Logged out successfully", | ||
success: true | ||
}); | ||
}; | ||
|
||
|
||
export const getOtherUsers = async (req, res) => { | ||
try { | ||
const loggedUserId = req.id; // Get the logged-in user ID from the request | ||
const otherUsers = await User.find({ _id: { $ne: loggedUserId } }).select("-password"); | ||
return res.status(200).json(otherUsers); | ||
} catch (error) { | ||
console.error(error); | ||
return res.status(500).json({ | ||
message: "Server error. Please try again later.", | ||
success: false | ||
}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import express from 'express'; | ||
import dotenv from 'dotenv'; | ||
import cors from 'cors'; | ||
import cookieParser from 'cookie-parser'; | ||
import userRoute from './route/userRoute.js'; | ||
import messageRoute from './route/messageRoute.js'; | ||
import databaseConnection from './utils/database.js'; | ||
import { app, server } from "./socket/socket.js"; | ||
import path from 'path' | ||
|
||
dotenv.config(); | ||
|
||
const __dirname = path.resolve(); | ||
const PORT = process.env.PORT || 3000; | ||
|
||
// Middleware | ||
app.use(cors({ | ||
origin: 'http://localhost:5173', | ||
credentials: true | ||
})); | ||
app.use(cookieParser()); | ||
app.use(express.urlencoded({ extended: true })); | ||
app.use(express.json()); | ||
|
||
// Routes | ||
app.use("/api/v1/user", userRoute); | ||
app.use("/api/v1/message", messageRoute); | ||
app.use(express.static(path.join(__dirname, "/frontend/dist"))); | ||
app.get("*", (req,res)=>{ | ||
res.sendFile(path.resolve(__dirname, "frontend", "dist", "index.html")); | ||
}) | ||
|
||
server.listen(PORT, () => { | ||
databaseConnection(); | ||
console.log(`Server listening on port ${PORT}`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import jwt from "jsonwebtoken"; | ||
|
||
|
||
const isAuth = async (req, res, next) => { | ||
try { | ||
const token = req.cookies.token; | ||
if (!token) { | ||
return res.status(401).json({ message: "User not authenticated." }); | ||
} | ||
|
||
// Verify the token | ||
const decoded = jwt.verify(token, process.env.TOKEN_SECRET); | ||
if (!decoded) { | ||
return res.status(401).json({ message: "Invalid token" }); | ||
} | ||
|
||
// Attach user ID to req.id | ||
req.id = decoded.userId; // Using req.id is fine if this is how you want it | ||
|
||
next(); | ||
} catch (error) { | ||
console.log(error); | ||
return res.status(500).json({ message: "Internal server error" }); | ||
} | ||
}; | ||
|
||
|
||
export default isAuth; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import mongoose from "mongoose"; | ||
|
||
const conversationModel = new mongoose.Schema({ | ||
participants:[{ | ||
type:mongoose.Schema.Types.ObjectId, | ||
ref:"User" | ||
}], | ||
messages:[{ | ||
type:mongoose.Schema.Types.ObjectId, | ||
ref:"Message" | ||
}] | ||
|
||
},{timestamps:true}) | ||
export const Conversation = mongoose.model("Conversation",conversationModel); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import mongoose from "mongoose"; | ||
|
||
const messageSchema = new mongoose.Schema({ | ||
senderId: { | ||
type: mongoose.Schema.Types.ObjectId, | ||
ref: "User", | ||
required: true | ||
}, | ||
receiverId: { | ||
type: mongoose.Schema.Types.ObjectId, | ||
ref: "User", | ||
required: true | ||
}, | ||
message: { | ||
type: String, | ||
required: true | ||
}, | ||
deletedBy: [ | ||
{ | ||
type: mongoose.Schema.Types.ObjectId, | ||
ref: "User", | ||
} | ||
] | ||
}, { timestamps: true }); | ||
|
||
export const Message = mongoose.model("Message", messageSchema); |
Oops, something went wrong.