mkcart / backend /controllers /userController.js
Kumar
updated
c2efbe6
const User = require("../models/userModel.js");
const asyncHandler = require("express-async-handler");
const generateToken = require("../utils/generateToken.js");
const jwt = require("jsonwebtoken");
const createUser = async (req, res, next) => {
const { name, email, password, dateOfBirth, gender, country } = req.body;
console.log('User registration attempt:', { name, email, dateOfBirth, gender, country });
if (!name || !email || !password) {
res.status(400);
const err = new Error("Please provide name, email and password");
return next(err);
}
if (password.length < 6) {
res.status(400);
const err = new Error("Password must be atleast 6 characters");
return next(err);
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
res.status(400);
const err = new Error("Invalid email address");
return next(err);
}
try {
const userExists = await User.findOne({ email });
if (userExists) {
res.status(400);
const err = new Error(
"Email is already registered. Please use a different email address"
);
return next(err);
}
const user = await User.create({
name,
email,
password,
dateOfBirth: dateOfBirth || '',
gender: gender || '',
country: country || '',
createdAt: new Date(),
});
if (user) {
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET_KEY, {
expiresIn: "10d",
});
generateToken(res, user._id);
res.status(201).json({
_id: user._id,
name: user.name,
email: user.email,
dateOfBirth: user.dateOfBirth,
gender: user.gender,
country: user.country,
token: token,
});
}
} catch (error) {
console.log(error);
if (error.code === 11000) {
res.status(400);
const err = new Error(
"Email is already registered. Please use a different email address..."
);
return next(err);
}
res.status(500).json({ error: error.message } || "Internal server error");
}
};
const login = asyncHandler(async (req, res) => {
const { email, password } = req.body;
console.log('Login attempt for:', email);
const user = await User.findOne({ email });
if (user && (await user.checkPassword(password))) {
console.log('Password check passed for user:', user._id);
try {
await User.findByIdAndUpdate(user._id, {
$set: { isActive: true, lastLogin: new Date() }
});
} catch (e) {
console.error('Failed to update user active state/lastLogin:', e);
}
try {
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET_KEY, {
expiresIn: "10d",
});
console.log('Token generated successfully:', token ? 'YES' : 'NO');
console.log('JWT_SECRET_KEY exists:', !!process.env.JWT_SECRET_KEY);
generateToken(res, user._id);
const responseData = {
_id: user._id,
name: user.name,
email: user.email,
dateOfBirth: user.dateOfBirth,
gender: user.gender,
country: user.country,
token: token,
};
console.log('Sending response with token:', !!responseData.token);
res.status(200).json(responseData);
} catch (tokenError) {
console.error('Error generating token:', tokenError);
res.status(500).json({ error: 'Failed to generate authentication token' });
}
} else {
console.log('Login failed for:', email);
res.status(400);
throw new Error("Invalid email or password");
}
});
const logout = asyncHandler(async (req, res) => {
const isProduction = process.env.NODE_ENV === 'production';
try {
if (req.user?._id) {
await User.findByIdAndUpdate(req.user._id, { $set: { isActive: false } });
}
} catch (e) {
console.error('Failed to mark user inactive on logout:', e);
}
const cookieOptions = {
httpOnly: true,
expires: new Date(0),
path: '/',
sameSite: isProduction ? 'none' : 'lax',
secure: isProduction,
...(isProduction && process.env.COOKIE_DOMAIN && {
domain: process.env.COOKIE_DOMAIN
})
};
res.cookie("token", "", cookieOptions);
res.status(200).json({ message: "Logged out.." });
});
const getProfile = asyncHandler(async (req, res) => {
const user = {
_id: req.user._id,
name: req.user.name,
email: req.user.email,
dateOfBirth: req.user.dateOfBirth,
gender: req.user.gender,
country: req.user.country,
};
res.status(200).json(user);
});
const updateProfile = asyncHandler(async (req, res) => {
const { password } = req.body;
if (password && password.length < 6) {
res.status(400);
throw new Error("Password must be at least 6 characters");
}
const user = await User.findById(req.user._id);
if (user) {
user.name = req.body.name || user.name;
if (password) {
user.password = password;
}
const updatedUser = await user.save();
res.status(200).json({
_id: updatedUser._id,
name: updatedUser.name,
email: updatedUser.email,
});
} else {
res.status(404);
throw new Error("User not found.");
}
});
const getWishlist = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const user = await User.findById(req.user._id).populate("wishlist");
res.json({ wishlist: user.wishlist });
});
const createWishlistItem = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { productId } = req.body;
if (!productId) {
res.status(400);
throw new Error("Missing productId in request body");
}
const user = await User.findById(req.user._id);
if (!user.wishlist.some(item => item.productId && item.productId.toString() === productId.toString())) {
const Product = require('../models/productModel');
const product = await Product.findById(productId);
if (!product) {
res.status(404);
throw new Error("Product not found");
}
user.wishlist.push({
productId: product._id,
name: product.name,
price: Number(product.price),
category: product.category,
seller: product.seller,
stock: product.stock,
image: product.images && product.images.length > 0 ? product.images[0].image : '',
ratings: Number(product.ratings),
createdAt: new Date()
});
await user.save();
}
res.json({ wishlist: user.wishlist });
});
const deleteWishlistItem = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { productId } = req.body;
const user = await User.findById(req.user._id);
user.wishlist = user.wishlist.filter(
(item) => item.productId && item.productId.toString() !== productId.toString()
);
await user.save();
res.json({ wishlist: user.wishlist });
});
const updateWishlist = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { wishlistIndex, update } = req.body;
const user = await User.findById(req.user._id);
if (user.wishlist[wishlistIndex]) {
Object.assign(user.wishlist[wishlistIndex], update);
await user.save();
res.json({ success: true, wishlist: user.wishlist[wishlistIndex] });
} else {
res.status(404);
throw new Error("Wishlist item not found");
}
});
const getWishlists = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const user = await User.findById(req.user._id).populate("wishlist");
res.json({ wishlist: user.wishlist });
});
const createWishlistItems = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { productIds } = req.body;
if (!Array.isArray(productIds) || productIds.length === 0) {
res.status(400);
throw new Error("Missing productIds array in request body");
}
const user = await User.findById(req.user._id);
const Product = require('../models/productModel');
for (const productId of productIds) {
if (!user.wishlist.some(item => item.productId && item.productId.toString() === productId.toString())) {
const product = await Product.findById(productId);
if (product) {
user.wishlist.push({
productId: product._id,
name: product.name,
price: Number(product.price),
category: product.category,
seller: product.seller,
stock: product.stock,
image: product.images && product.images.length > 0 ? product.images[0].image : '',
ratings: Number(product.ratings),
createdAt: new Date()
});
}
}
}
await user.save();
res.json({ wishlist: user.wishlist });
});
const deleteWishlistItems = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { productIds } = req.body;
if (!Array.isArray(productIds) || productIds.length === 0) {
res.status(400);
throw new Error("Missing productIds array in request body");
}
const user = await User.findById(req.user._id);
user.wishlist = user.wishlist.filter(
(item) => !productIds.includes(item.productId?.toString())
);
await user.save();
res.json({ wishlist: user.wishlist });
});
const updateWishlists = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { updates } = req.body;
if (!Array.isArray(updates) || updates.length === 0) {
res.status(400);
throw new Error("Missing updates array in request body");
}
const user = await User.findById(req.user._id);
for (const { productId, update } of updates) {
const item = user.wishlist.find(item => item.productId && item.productId.toString() === productId.toString());
if (item) {
Object.assign(item, update);
}
}
await user.save();
res.json({ wishlist: user.wishlist });
});
const getReviews = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const user = await User.findById(req.user._id).populate("reviews.product");
res.json({ reviews: user.reviews });
});
const addReview = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { productId, rating, comment } = req.body;
const user = await User.findById(req.user._id);
user.reviews.push({ product: productId, rating, comment });
await user.save();
res.json({ reviews: user.reviews });
});
const deleteReview = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { reviewId } = req.body;
const user = await User.findById(req.user._id);
user.reviews = user.reviews.filter(
(r) => r._id.toString() !== reviewId.toString()
);
await user.save();
res.json({ reviews: user.reviews });
});
const getOrders = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const user = await User.findById(req.user._id);
res.json({ orders: user.orders });
});
const getOrderById = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { orderId } = req.params;
const user = await User.findById(req.user._id);
const order = user.orders.find(order =>
order._id.toString() === orderId ||
(order.createdAt && order.createdAt.toISOString() === orderId)
);
if (order) {
res.json({ success: true, order });
} else {
res.status(404).json({ success: false, message: "Order not found" });
}
});
const createOrderSnapshot = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { order } = req.body;
const orderToSave = {
...order,
shippingAddress: order.shippingAddress || null,
paymentMethod: order.paymentMethod || null,
};
const user = await User.findById(req.user._id);
user.orders.push(orderToSave);
await user.save();
const newOrder = user.orders[user.orders.length - 1];
res.json({ success: true, order: newOrder, orders: user.orders });
});
const deleteOrderSnapshot = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { createdAt } = req.body;
const user = await User.findById(req.user._id);
const initialLength = user.orders.length;
user.orders = user.orders.filter(order => order.createdAt && order.createdAt.toISOString() !== createdAt);
if (user.orders.length === initialLength) {
return res.status(404).json({ message: "Order not found" });
}
await user.save();
res.json({ orders: user.orders });
});
const updateOrderSnapshot = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { createdAt, update } = req.body;
const user = await User.findById(req.user._id);
const order = user.orders.find(order => order.createdAt && order.createdAt.toISOString() === createdAt);
if (order) {
Object.assign(order, update);
await user.save();
res.json({ order, orders: user.orders });
} else {
res.status(404);
throw new Error("Order not found in user history");
}
});
const getCarts = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const user = await User.findById(req.user._id);
res.json({ carts: user.carts });
});
const createCartSnapshot = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { cart } = req.body;
if (!cart || !Array.isArray(cart.cartItems) || cart.cartItems.length === 0) {
res.status(400);
throw new Error("Missing or invalid cart in request body");
}
for (const item of cart.cartItems) {
if (!item.productId || typeof item.qty !== 'number') {
res.status(400);
throw new Error("Each cart item must have a productId and qty");
}
}
const user = await User.findById(req.user._id);
user.carts.push(cart);
await user.save();
res.json({ success: true, carts: user.carts });
});
const deleteCartSnapshot = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { createdAt } = req.body;
const user = await User.findById(req.user._id);
const initialLength = user.carts.length;
user.carts = user.carts.filter(cart => cart.createdAt && cart.createdAt.toISOString() !== createdAt);
if (user.carts.length === initialLength) {
return res.status(404).json({ message: "Cart not found" });
}
await user.save();
res.json({ carts: user.carts });
});
const updateCartSnapshot = asyncHandler(async (req, res) => {
if (!req.user || !req.user._id) {
return res.status(401).json({ message: "Not authorized, user not found" });
}
const { createdAt, update } = req.body;
const user = await User.findById(req.user._id);
const cart = user.carts.find(cart => cart.createdAt && cart.createdAt.toISOString() === createdAt);
if (cart) {
Object.assign(cart, update);
await user.save();
res.json({ cart, carts: user.carts });
} else {
res.status(404);
throw new Error("Cart not found in user history");
}
});
module.exports = { createUser, login, logout, getProfile, updateProfile, getWishlist, createWishlistItem, deleteWishlistItem, updateWishlist, getWishlists, createWishlistItems, deleteWishlistItems, updateWishlists, getOrders, getOrderById, createOrderSnapshot, deleteOrderSnapshot, updateOrderSnapshot, getCarts, createCartSnapshot, deleteCartSnapshot, updateCartSnapshot, getReviews, addReview, deleteReview };