Skip to main content
Glama

code-index-mcp

User.js8.47 kB
const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const { v4: uuidv4 } = require('uuid'); // User roles enumeration const USER_ROLES = { ADMIN: 'admin', USER: 'user', GUEST: 'guest', }; // User status enumeration const USER_STATUS = { ACTIVE: 'active', INACTIVE: 'inactive', SUSPENDED: 'suspended', DELETED: 'deleted', }; // User schema definition const userSchema = new mongoose.Schema( { id: { type: String, default: uuidv4, unique: true, required: true, }, username: { type: String, required: [true, 'Username is required'], unique: true, minlength: [3, 'Username must be at least 3 characters'], maxlength: [20, 'Username cannot exceed 20 characters'], match: [/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores'], }, email: { type: String, unique: true, sparse: true, match: [/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, 'Please enter a valid email'], }, name: { type: String, required: [true, 'Name is required'], minlength: [1, 'Name is required'], maxlength: [100, 'Name cannot exceed 100 characters'], }, age: { type: Number, min: [0, 'Age cannot be negative'], max: [150, 'Age cannot exceed 150'], }, password: { type: String, required: [true, 'Password is required'], minlength: [8, 'Password must be at least 8 characters'], select: false, // Don't include in queries by default }, role: { type: String, enum: Object.values(USER_ROLES), default: USER_ROLES.USER, }, status: { type: String, enum: Object.values(USER_STATUS), default: USER_STATUS.ACTIVE, }, lastLogin: { type: Date, default: null, }, loginAttempts: { type: Number, default: 0, }, permissions: { type: [String], default: [], }, metadata: { type: mongoose.Schema.Types.Mixed, default: {}, }, }, { timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true }, } ); // Virtual for user response (without sensitive data) userSchema.virtual('response').get(function() { return { id: this.id, username: this.username, email: this.email, name: this.name, age: this.age, role: this.role, status: this.status, lastLogin: this.lastLogin, permissions: this.permissions, metadata: this.metadata, createdAt: this.createdAt, updatedAt: this.updatedAt, }; }); // Virtual for checking if user is active userSchema.virtual('isActive').get(function() { return this.status === USER_STATUS.ACTIVE; }); // Virtual for checking if user is admin userSchema.virtual('isAdmin').get(function() { return this.role === USER_ROLES.ADMIN; }); // Virtual for checking if user is locked userSchema.virtual('isLocked').get(function() { return this.loginAttempts >= 5 || this.status === USER_STATUS.SUSPENDED; }); // Pre-save middleware to hash password userSchema.pre('save', async function(next) { // Only hash the password if it has been modified (or is new) if (!this.isModified('password')) return next(); try { // Hash password with cost of 12 const hashedPassword = await bcrypt.hash(this.password, 12); this.password = hashedPassword; next(); } catch (error) { next(error); } }); // Instance method to check password userSchema.methods.checkPassword = async function(candidatePassword) { return await bcrypt.compare(candidatePassword, this.password); }; // Instance method to generate JWT token userSchema.methods.generateToken = function() { return jwt.sign( { id: this.id, username: this.username, role: this.role }, process.env.JWT_SECRET || 'fallback-secret', { expiresIn: process.env.JWT_EXPIRES_IN || '24h', issuer: 'user-management-system' } ); }; // Instance method to add permission userSchema.methods.addPermission = function(permission) { if (!this.permissions.includes(permission)) { this.permissions.push(permission); } }; // Instance method to remove permission userSchema.methods.removePermission = function(permission) { this.permissions = this.permissions.filter(p => p !== permission); }; // Instance method to check permission userSchema.methods.hasPermission = function(permission) { return this.permissions.includes(permission); }; // Instance method to record successful login userSchema.methods.recordLogin = function() { this.lastLogin = new Date(); this.loginAttempts = 0; }; // Instance method to record failed login attempt userSchema.methods.recordFailedLogin = function() { this.loginAttempts += 1; if (this.loginAttempts >= 5) { this.status = USER_STATUS.SUSPENDED; } }; // Instance method to reset login attempts userSchema.methods.resetLoginAttempts = function() { this.loginAttempts = 0; }; // Instance method to activate user userSchema.methods.activate = function() { this.status = USER_STATUS.ACTIVE; this.loginAttempts = 0; }; // Instance method to deactivate user userSchema.methods.deactivate = function() { this.status = USER_STATUS.INACTIVE; }; // Instance method to suspend user userSchema.methods.suspend = function() { this.status = USER_STATUS.SUSPENDED; }; // Instance method to delete user (soft delete) userSchema.methods.delete = function() { this.status = USER_STATUS.DELETED; }; // Instance method to get metadata userSchema.methods.getMetadata = function(key, defaultValue = null) { return this.metadata[key] || defaultValue; }; // Instance method to set metadata userSchema.methods.setMetadata = function(key, value) { this.metadata[key] = value; }; // Instance method to remove metadata userSchema.methods.removeMetadata = function(key) { delete this.metadata[key]; }; // Instance method to validate user data userSchema.methods.validateUser = function() { const errors = []; if (!this.username || this.username.length < 3) { errors.push('Username must be at least 3 characters'); } if (!this.name || this.name.length === 0) { errors.push('Name is required'); } if (this.age && (this.age < 0 || this.age > 150)) { errors.push('Age must be between 0 and 150'); } if (this.email && !this.email.match(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/)) { errors.push('Email format is invalid'); } return errors; }; // Static method to find by username userSchema.statics.findByUsername = function(username) { return this.findOne({ username }); }; // Static method to find by email userSchema.statics.findByEmail = function(email) { return this.findOne({ email }); }; // Static method to find active users userSchema.statics.findActive = function() { return this.find({ status: USER_STATUS.ACTIVE }); }; // Static method to find by role userSchema.statics.findByRole = function(role) { return this.find({ role }); }; // Static method to search users userSchema.statics.searchUsers = function(query, options = {}) { const searchRegex = new RegExp(query, 'i'); const searchQuery = { $or: [ { username: searchRegex }, { name: searchRegex }, { email: searchRegex }, ], }; return this.find(searchQuery, null, options); }; // Static method to get user statistics userSchema.statics.getUserStats = async function() { const stats = await this.aggregate([ { $group: { _id: null, total: { $sum: 1 }, active: { $sum: { $cond: [{ $eq: ['$status', USER_STATUS.ACTIVE] }, 1, 0] } }, admin: { $sum: { $cond: [{ $eq: ['$role', USER_ROLES.ADMIN] }, 1, 0] } }, user: { $sum: { $cond: [{ $eq: ['$role', USER_ROLES.USER] }, 1, 0] } }, guest: { $sum: { $cond: [{ $eq: ['$role', USER_ROLES.GUEST] }, 1, 0] } }, withEmail: { $sum: { $cond: [{ $ne: ['$email', null] }, 1, 0] } }, }, }, ]); return stats[0] || { total: 0, active: 0, admin: 0, user: 0, guest: 0, withEmail: 0, }; }; // Index for performance userSchema.index({ username: 1 }); userSchema.index({ email: 1 }); userSchema.index({ role: 1 }); userSchema.index({ status: 1 }); userSchema.index({ createdAt: -1 }); // Export model and constants const User = mongoose.model('User', userSchema); module.exports = { User, USER_ROLES, USER_STATUS, };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/johnhuang316/code-index-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server