Skip to content

Commit

Permalink
c1
Browse files Browse the repository at this point in the history
  • Loading branch information
KhushiPandey8 committed Dec 10, 2024
0 parents commit 8e091eb
Show file tree
Hide file tree
Showing 49 changed files with 11,209 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Chat-App
This is Full stack chat app
95 changes: 95 additions & 0 deletions backend/controllers/messageController.js
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" });
}
};
143 changes: 143 additions & 0 deletions backend/controllers/userContoller.js
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
});
}
};
36 changes: 36 additions & 0 deletions backend/index.js
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}`);
});
29 changes: 29 additions & 0 deletions backend/middleware/isAuth.js
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;

14 changes: 14 additions & 0 deletions backend/model/conversationModel.js
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);
26 changes: 26 additions & 0 deletions backend/model/messageModel.js
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);
Loading

0 comments on commit 8e091eb

Please sign in to comment.