Source: controllers/userController.js

/**
 * @file Controller for user-related operations like registration and login.
 * @module controllers/userController
 * @requires ../models/userModel
 * @requires jsonwebtoken
 */

const User = require("../models/userModel");
const jwt = require("jsonwebtoken");

/**
 * Generates a JSON Web Token (JWT) for a given user ID.
 *
 * @private
 * @param {string} id - The user's unique identifier from MongoDB.
 * @returns {string} The generated JWT, valid for 30 days.
 */
const generateToken = (id) => {
  return jwt.sign({ id }, process.env.JWT_SECRET, {
    expiresIn: "30d",
  });
};

/**
 * Registers a new user.
 *
 * - Validates that the email is unique.
 * - Creates a new user in the database.
 * - Returns user details and a JWT on success.
 *
 * @async
 * @route POST /api/users/register
 * @access Public
 * @param {Object} req - Express request object (contains `name`, `email`, `password`, and optional `role` in `body`).
 * @param {Object} res - Express response object.
 * @returns {Promise<void>}
 */
exports.registerUser = async (req, res) => {
  const { name, email, password, role } = req.body;

  try {
    const userExists = await User.findOne({ email });

    if (userExists) {
      return res
        .status(400)
        .json({ message: "User with this email already exists" });
    }

    const user = await User.create({ name, email, password, role });

    if (user) {
      res.status(201).json({
        _id: user._id,
        name: user.name,
        email: user.email,
        role: user.role,
        token: generateToken(user._id),
      });
    } else {
      res.status(400).json({ message: "Invalid user data" });
    }
  } catch (error) {
    res.status(500).json({ message: "Server Error", error: error.message });
  }
};

/**
 * Authenticates an existing user and returns a JWT.
 *
 * - Verifies email and password.
 * - Returns user details and a JWT if credentials are valid.
 *
 * @async
 * @route POST /api/users/login
 * @access Public
 * @param {Object} req - Express request object (contains `email` and `password` in `body`).
 * @param {Object} res - Express response object.
 * @returns {Promise<void>}
 */
exports.loginUser = async (req, res) => {
  const { email, password } = req.body;

  try {
    const user = await User.findOne({ email });

    if (user && (await user.matchPassword(password))) {
      res.json({
        _id: user._id,
        name: user.name,
        email: user.email,
        role: user.role,
        token: generateToken(user._id),
      });
    } else {
      res.status(401).json({ message: "Invalid email or password" });
    }
  } catch (error) {
    res.status(500).json({ message: "Server Error", error: error.message });
  }
};