Source: models/userModel.js

/**
 * @file Defines the Mongoose schema and model for a User.
 * @module models/userModel
 * @requires mongoose
 * @requires bcryptjs
 */

const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");

/**
 * @typedef User
 * @property {string} name - The name of the user (required).
 * @property {string} email - The unique email of the user (required).
 * @property {string} password - The hashed password of the user (required).
 * @property {"user"|"admin"} role - The role of the user (defaults to "user").
 * @property {Date} createdAt - Timestamp when the user was created (auto-generated).
 * @property {Date} updatedAt - Timestamp when the user was last updated (auto-generated).
 */

/**
 * Mongoose schema for the User collection.
 * @constant
 * @type {mongoose.Schema<User>}
 */
const userSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true,
    },
    email: {
      type: String,
      required: true,
      unique: true,
    },
    password: {
      type: String,
      required: true,
    },
    role: {
      type: String,
      enum: ["user", "admin"],
      default: "user",
    },
  },
  {
    timestamps: true,
  }
);

/**
 * Pre-save hook: Hashes the user's password if it has been modified.
 * @function
 * @memberof module:models/userModel~userSchema
 * @this mongoose.Document & { password: string, isModified: Function }
 * @param {mongoose.HookNextFunction} next - The next middleware function.
 */
userSchema.pre("save", async function (next) {
  if (!this.isModified("password")) {
    return next();
  }
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
  next();
});

/**
 * Compare an entered password with the user's hashed password.
 * @function
 * @name matchPassword
 * @memberof module:models/userModel~userSchema.methods
 * @param {string} enteredPassword - The password to compare.
 * @returns {Promise<boolean>} True if the passwords match, false otherwise.
 */
userSchema.methods.matchPassword = async function (enteredPassword) {
  return bcrypt.compare(enteredPassword, this.password);
};

/**
 * The Mongoose model for a User, compiled from the userSchema.
 * @type {mongoose.Model<User>}
 */
const User = mongoose.model("User", userSchema);

module.exports = User;