Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 121 additions & 133 deletions server/controllers/user.controllers.js
Original file line number Diff line number Diff line change
@@ -1,147 +1,135 @@
import ApiError from "../utils/ApiError.js";
import ApiResponse from "../utils/ApiResponse.js";
import asyncHandler from "../utils/asyncHandler.js";
import { User } from "../models/user.models.js";
import jwt from "jsonwebtoken";

const generateAccessAndRefreshToken = async (user) => {
const accessToken = await user.generateAccessToken();
const refreshToken = await user.generateRefreshToken();
user.refreshToken = refreshToken;
// Skip validation since only partial fields are updated (other required fields may be missing)
await user.save({
validateBeforeSave: false,
});
const generateAccessAndRefreshTokens = async (userId) => {
try {
const user = await User.findById(userId);
const accessToken = await user.generateAccessToken();
const refreshToken = await user.generateRefreshToken();

return { accessToken: accessToken, refreshToken: refreshToken };
};

const registerUser = asyncHandler(async (req, res) => {
const { username, email, password, fullName } = req.body;

// Checking if the each and every field that it's not empty
if (
[username, email, password, fullName].some((field) => field?.trim() === "")
) {
//if Any of the field is empty it will throw and exception
throw new ApiError(400, "All the fields are required");
}
const isUserExists = await User.findOne({ $or: [{ username }, { email }] });
if (isUserExists) {
// Just a simple if else check if both the name and email have already been created and throws error based on the condition

// if (isUserExists.username === username && isUserExists.email === email) {
// throw new ApiError(
// 401,
// "User with the following username or email exists"
// );
// } else if (
// isUserExists.username === username &&
// !isUserExists.email === email
// ) {
// throw new ApiError(401, "User with the following username exists");
// } else throw new ApiError(401, "User with the following email exists");

// ***** More cleaner version ***** //

let conflictField = [];

if (isUserExists.username === username.toLowerCase())
conflictField.push("username");
if (isUserExists.email === email) conflictField.push("email");

const message = `User with this ${conflictField.join(
" and "
)} already exists`;
throw new ApiError(401, message);
}
user.refreshToken = refreshToken;
await user.save({ validateBeforeSave: false });

//If not already exists create a new user with their credentials
const user = await User.create({
username: username.toLowerCase(),
email,
password,
fullName,
});
if (!user) {
throw new ApiError(
500,
"Something went wrong while creating user in the database"
);
return { accessToken, refreshToken };
} catch (error) {
throw new Error("Something went wrong while generating tokens");
}
};

const createdUser = await User.findById(user._id).select(
"-password -refreshToken"
);

//Fallback checking if for any reason the user has been deleted

if (!createdUser) {
throw new ApiError(
500,
"Something went wrong while fetching user from the database"
);
const registerUser = async (req, res) => {
try {
const { fullName, email, username, password } = req.body;

// Validation
if ([fullName, email, username, password].some((field) => field?.trim() === "")) {
return res.status(400).json({ message: "All fields are required" });
}

// Check if user already exists
const existedUser = await User.findOne({
$or: [{ username }, { email }]
});

if (existedUser) {
return res.status(409).json({ message: "User with email or username already exists" });
}

// Create user
const user = await User.create({
fullName,
email,
username: username.toLowerCase(),
password,
});

const createdUser = await User.findById(user._id).select("-password -refreshToken");

if (!createdUser) {
return res.status(500).json({ message: "Something went wrong while registering user" });
}

return res.status(201).json({
message: "User registered successfully",
user: createdUser
});
} catch (error) {
return res.status(500).json({ message: error.message });
}
return res
.status(201)
.json(new ApiResponse(200, createdUser, "User registered successfully"));
});

const loginUser = asyncHandler(async (req, res) => {
const { username, email, password } = req.body;
//Any one field is required
if (!username && !email) {
throw new ApiError(400, "Username or email is required");
}
const user = await User.findOne({
$or: [{ email }, { username }],
});
};

if (!user) {
throw new ApiError(404, "No user with the current username or email");
const loginUser = async (req, res) => {
try {
const { email, username, password } = req.body;

if (!username && !email) {
return res.status(400).json({ message: "Username or email is required" });
}

const user = await User.findOne({
$or: [{ username }, { email }]
});

if (!user) {
return res.status(404).json({ message: "User does not exist" });
}

const isPasswordValid = await user.isPasswordCorrect(password);

if (!isPasswordValid) {
return res.status(401).json({ message: "Invalid user credentials" });
}

const { accessToken, refreshToken } = await generateAccessAndRefreshTokens(user._id);

const loggedInUser = await User.findById(user._id).select("-password -refreshToken");

const options = {
httpOnly: true,
secure: true,
};

return res
.status(200)
.cookie("accessToken", accessToken, options)
.cookie("refreshToken", refreshToken, options)
.json({
message: "User logged in successfully",
user: loggedInUser,
accessToken,
refreshToken
});
} catch (error) {
return res.status(500).json({ message: error.message });
}
};

const isPasswordCorrect = await user.isPasswordCorrect(password);
const logoutUser = async (req, res) => {
try {
await User.findByIdAndUpdate(
req.user._id,
{
$unset: {
refreshToken: 1
}
},
{
new: true
}
);

if (!isPasswordCorrect) {
throw new ApiError(401, "Invalid password");
const options = {
httpOnly: true,
secure: true,
};

return res
.status(200)
.clearCookie("accessToken", options)
.clearCookie("refreshToken", options)
.json({ message: "User logged out successfully" });
} catch (error) {
return res.status(500).json({ message: error.message });
}
//Generating user access and refresh tokens
const { accessToken, refreshToken } = await generateAccessAndRefreshToken(
user
);

const loggedInUser = await User.findById(user._id).select(
"-password -refreshToken"
);
const options = {
httpOnly: true,
secure: true,
};
return res
.status(200)
.cookie("accessToken", accessToken, options)
.cookie("refreshToken", refreshToken, options)
.json(new ApiResponse(200, loggedInUser, "User logged in successfully"));
});

const logoutUser = asyncHandler(async (req, res) => {
await User.findByIdAndUpdate(
req.user._id,
{ $set: { refreshToken: undefined } }

// Returns the updated document
// { new: true }
);
const options = {
httpOnly: true,
secure: true,
};

return res
.status(200)
.clearCookie("accessToken", options)
.clearCookie("refreshToken", options)
.json(new ApiResponse(200, {}, "User logged out"));
});
};

export { registerUser, loginUser, logoutUser };
27 changes: 10 additions & 17 deletions server/middlewares/auth.middleware.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
import { User } from "../models/user.models.js";
import asyncHandler from "../utils/asyncHandler.js";
import ApiError from "../utils/ApiError.js";
import jwt from "jsonwebtoken";
import { User } from "../models/user.models.js";

export const verifyUser = asyncHandler(async (req, res, next) => {
export const verifyUser = async (req, res, next) => {
try {
// Fetching tokens either from cookies or header
const token =
req.cookies?.accessToken ||
req.header("Authorization")?.replace("Bearer ", "");
const token = req.cookies?.accessToken || req.header("Authorization")?.replace("Bearer ", "");

if (!token) {
throw new ApiError(401, "Unauthorized request");
return res.status(401).json({ message: "Unauthorized request" });
}

// Decoded token contains id, email and username
// This might throw error so wrap it in a try catch
const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET);

const user = await User.findById(decodedToken?._id).select(
"-password -refreshToken"
);
const user = await User.findById(decodedToken?._id).select("-password -refreshToken");

if (!user) {
throw new ApiError(401, "Invalid Access Token");
return res.status(401).json({ message: "Invalid access token" });
}

req.user = user;
next();
} catch (error) {
throw new ApiError(401, error?.message || "Invalid access token");
return res.status(401).json({ message: error?.message || "Invalid access token" });
}
});
};
Loading