const jwt = require('jsonwebtoken'); const User = require('../models/userModel'); const { validateEmail, validatePassword } = require('../middleware/validationMiddleware'); // Generate JWT Token const generateToken = (id) => { return jwt.sign({ id }, process.env.JWT_SECRET || 'your_secret_key', { expiresIn: process.env.JWT_EXPIRE || '7d', }); }; // @desc Register user // @route POST /api/auth/register // @access Public exports.register = async (req, res) => { try { const { firstName, lastName, email, password, passwordConfirm } = req.body; const normalizedEmail = email ? email.toLowerCase().trim() : ''; // Validation if (!firstName || !lastName || !email || !password || !passwordConfirm) { return res.status(400).json({ message: 'All fields are required' }); } if (!validateEmail(normalizedEmail)) { return res.status(400).json({ message: 'Invalid email format' }); } if (!validatePassword(password)) { return res.status(400).json({ message: 'Password must be at least 6 characters', }); } if (password !== passwordConfirm) { return res.status(400).json({ message: 'Passwords do not match' }); } // Check if user already exists let user = await User.findOne({ email: normalizedEmail }); if (user) { return res.status(400).json({ message: 'Email already in use' }); } // Create user user = await User.create({ firstName, lastName, email: normalizedEmail, password, }); // Create token const token = generateToken(user._id); res.status(201).json({ success: true, message: 'User registered successfully', token, user: user.getPublicData(), }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Login user // @route POST /api/auth/login // @access Public exports.login = async (req, res) => { try { const { email, password } = req.body; const normalizedEmail = email ? email.toLowerCase().trim() : ''; // Validation if (!email || !password) { return res.status(400).json({ message: 'Email and password are required' }); } if (!validateEmail(normalizedEmail)) { return res.status(400).json({ message: 'Invalid email format' }); } const user = await User.findOne({ email: normalizedEmail }); if (!user) { return res.status(401).json({ message: 'Invalid email or password' }); } // Check if password matches const isPasswordMatch = await user.matchPassword(password); if (!isPasswordMatch) { return res.status(401).json({ message: 'Invalid email or password' }); } // Check if user account is active if (!user.isActive) { return res.status(403).json({ message: 'Your account has been deactivated' }); } // Update last login user.lastLogin = new Date(); await user.save(); // Create token const token = generateToken(user._id); res.status(200).json({ success: true, message: 'Login successful', token, user: user.getPublicData(), }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Logout user (client-side) // @route POST /api/auth/logout // @access Private exports.logout = async (req, res) => { try { // Token removal is handled on client-side // This endpoint can be used for server-side session cleanup if needed res.status(200).json({ success: true, message: 'Logout successful', }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Refresh token // @route POST /api/auth/refresh-token // @access Private exports.refreshToken = async (req, res) => { try { const { token } = req.body; if (!token) { return res.status(400).json({ message: 'Token is required' }); } // Verify token let decoded; try { decoded = jwt.verify(token, process.env.JWT_SECRET || 'your_secret_key'); } catch (error) { return res.status(401).json({ message: 'Invalid or expired token' }); } // Get user const user = await User.findById(decoded.id); if (!user) { return res.status(404).json({ message: 'User not found' }); } // Generate new token const newToken = generateToken(user._id); res.status(200).json({ success: true, message: 'Token refreshed successfully', token: newToken, }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Get current logged in user // @route GET /api/auth/me // @access Private exports.getMe = async (req, res) => { try { const user = await User.findById(req.user._id); res.status(200).json({ success: true, user: user.getPublicData(), }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } };