@ideal-photography/shared
Version:
Shared GraphQL (Apollo Server v5) and Mongoose logic for Ideal Photography PWAs: users, products, services, bookings, orders/cart, galleries, reviews, notifications, campaigns, settings, and audit logs.
75 lines (64 loc) • 2.29 kB
JavaScript
import mongoose from 'mongoose';
import bcrypt from 'bcryptjs';
const adminSchema = new mongoose.Schema({
username: {
type: String,
required: [true, 'Username is required'],
unique: true,
trim: true,
minlength: [3, 'Username must be at least 3 characters']
},
password: {
type: String,
required: [true, 'Password is required'],
minlength: [6, 'Password must be at least 6 characters']
},
role: {
type: String,
enum: ['admin', 'manager', 'super_admin'],
default: 'admin'
},
permissions: [{ type: String }],
isActive: { type: Boolean, default: true },
isVerified: { type: Boolean, default: false },
verifiedBy: { type: mongoose.Schema.Types.ObjectId, ref: 'Admin' },
verifiedAt: { type: Date },
loginAttempts: { type: Number, default: 0 },
lockUntil: { type: Date },
lastLogin: { type: Date },
createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'Admin' }
}, {
timestamps: true
});
adminSchema.virtual('isLocked').get(function () {
return !!(this.lockUntil && this.lockUntil > Date.now());
});
adminSchema.index({ username: 1 }, { unique: true });
adminSchema.index({ role: 1 });
adminSchema.pre('save', async function (next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 12);
next();
});
adminSchema.methods.comparePassword = function (candidatePassword) {
return bcrypt.compare(candidatePassword, this.password);
};
adminSchema.methods.incLoginAttempts = function () {
if (this.lockUntil && this.lockUntil < Date.now()) {
return this.updateOne({
$unset: { lockUntil: 1 },
$set: { loginAttempts: 1 }
});
}
const updates = { $inc: { loginAttempts: 1 } };
if (this.loginAttempts + 1 >= 5 && !this.isLocked) {
updates.$set = { lockUntil: Date.now() + 2 * 60 * 60 * 1000 };
}
return this.updateOne(updates);
};
adminSchema.methods.resetLoginAttempts = function () {
return this.updateOne({
$unset: { loginAttempts: 1, lockUntil: 1 }
});
};
export default mongoose.model('Admin', adminSchema);