const bcrypt = require("bcryptjs"); const User = require("../models/userModel"); const jwt = require("jsonwebtoken"); const sendEmail = require("../services/email"); const generateToken = (id) => { return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: "30d" }); }; exports.SignUp = async (req, res) => { try { const { firstName, lastName, email, password, repeatPassword, captcha, role, } = req.body; if ( !firstName || !lastName || !email || !password || !repeatPassword || !captcha ) { return res.status(400).json({ message: "All fields are mandatory" }); } if (firstName.length < 2 || firstName.length > 50) return res .status(400) .json({ message: "First name must be 2-50 characters" }); if (lastName.length < 2 || lastName.length > 50) return res .status(400) .json({ message: "Last name must be 2-50 characters" }); if (password.length < 6 || password.length > 20) return res .status(400) .json({ message: "Password must be 6-20 characters" }); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) return res.status(400).json({ message: "Invalid email format" }); const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{6,}$/; if (!passwordRegex.test(password)) return res .status(400) .json({ message: "Password must contain letters and numbers" }); if (password !== repeatPassword) return res.status(400).json({ message: "Passwords do not match" }); // Temporary captcha validation if (!captcha) { return res.status(400).json({ message: "Captcha is required" }); } const existingUser = await User.findOne({ where: { email } }); if (existingUser) return res.status(400).json({ message: "Email already registered" }); const hashedPassword = await bcrypt.hash(password, 10); const newUser = await User.create({ role, firstName, lastName, email, password: hashedPassword, }); res.status(201).json({ message: `${role} registered successfully`, user: { id: newUser.id, role: newUser.role, firstName: newUser.firstName, lastName: newUser.lastName, email: newUser.email, token: generateToken(newUser.id), }, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server error", error: error.message }); } }; // Login Controller exports.login = async (req, res) => { try { const { email, password } = req.body; if (!email || !password) { return res .status(400) .json({ message: "Email and password are required" }); } const user = await User.findOne({ where: { email } }); if (!user) return res.status(404).json({ message: "User not found" }); const isMatch = await bcrypt.compare(password, user.password); if (!isMatch) return res.status(401).json({ message: "Invalid password" }); res.status(200).json({ message: "Login successful", user: { id: user.id, firstName: user.firstName, lastName: user.lastName, email: user.email, role: user.role, token: generateToken(user.id), }, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server error", error: error.message }); } }; // Get All Users exports.getAllUsers = async (req, res) => { try { const users = await User.findAll({ order: [["createdAt", "DESC"]], attributes: { exclude: ["password", "captcha"] }, }); res.status(200).json({ count: users.length, users }); } catch (error) { console.error(error); res.status(500).json({ message: "Server error", error: error.message }); } }; // Delete User exports.deleteUser = async (req, res) => { try { const { id } = req.params; const user = await User.findByPk(id); if (!user) { return res.status(404).json({ message: "User not found" }); } await user.destroy(); res.status(200).json({ message: `User with ID ${id} deleted successfully`, }); } catch (error) { console.error(error); res.status(500).json({ message: "Server error", error: error.message }); } }; // Step 1: Send OTP to user email exports.forgotPassword = async (req, res) => { try { const { email } = req.body; if (!email) return res.status(400).json({ message: "Email is required" }); const user = await User.findOne({ where: { email } }); if (!user) return res.status(404).json({ message: "User not found" }); // Generate 6-digit OTP const otp = Math.floor(100000 + Math.random() * 900000).toString(); user.resetOtp = otp; user.resetOtpExpire = Date.now() + 10 * 60 * 1000; // OTP valid for 10 min user.resetOtpVerified = false; // reset verification flag await user.save(); // Send OTP by email await sendEmail(`${user.firstName} ${user.lastName}`, email, otp); return res.status(200).json({ message: "OTP sent to your email" }); } catch (error) { console.error(error); return res.status(500).json({ message: "Server Error" }); } }; // Step 2: Verify OTP exports.verifyOtp = async (req, res) => { try { const { email, otp } = req.body; if (!email || !otp) return res.status(400).json({ message: "Email & OTP required" }); const user = await User.findOne({ where: { email } }); if (!user) return res.status(404).json({ message: "User not found" }); // Check OTP match and expiry if (user.resetOtp !== otp) return res.status(400).json({ message: "Invalid OTP" }); if (user.resetOtpExpire < Date.now()) return res.status(400).json({ message: "OTP expired" }); // Mark OTP as verified user.resetOtpVerified = true; await user.save(); return res.status(200).json({ message: "OTP verified successfully" }); } catch (error) { console.error(error); return res.status(500).json({ message: "Server Error" }); } }; // Step 3: Reset Password exports.resetPassword = async (req, res) => { try { const { email, newPassword, confirmPassword } = req.body; if (!email || !newPassword || !confirmPassword) return res.status(400).json({ message: "Email, new password & confirm password required" }); if (newPassword !== confirmPassword) return res.status(400).json({ message: "Passwords do not match" }); if (newPassword.length < 6) return res.status(400).json({ message: "Password must be at least 6 characters" }); const user = await User.findOne({ where: { email } }); if (!user) return res.status(404).json({ message: "User not found" }); // Check if OTP was verified if (!user.resetOtpVerified) return res.status(400).json({ message: "OTP not verified yet" }); // Hash new password const hashed = await bcrypt.hash(newPassword, 10); user.password = hashed; // Clear OTP fields user.resetOtp = null; user.resetOtpExpire = null; user.resetOtpVerified = false; await user.save(); return res.status(200).json({ message: "Password reset successful" }); } catch (err) { console.error(err); return res.status(500).json({ message: "Server Error" }); } };