Team Ai
Apppublic

sanket3280/code-execution

sourceHugging Faceupdated 11mo agoView on Hugging Face
0likes
User.js289 linesDownload Raw Back to models
1const mongoose = require('mongoose');2const bcrypt = require('bcryptjs');3const jwt = require('jsonwebtoken');4const { config } = require('../config/env.config');5 6const UserSchema = new mongoose.Schema({7  username: {8    type: String,9    required: [true, 'Please provide a username'],10    unique: true,11    trim: true,12    minlength: [3, 'Username must be at least 3 characters long'],13    maxlength: [20, 'Username cannot exceed 20 characters']14  },15  email: {16    type: String,17    required: [true, 'Please provide an email'],18    unique: true,19    match: [20      /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,21      'Please provide a valid email'22    ]23  },24  name: {25    type: String,26    default: ''27  },28  gender: {29    type: String,30    enum: ['', 'Male', 'Female', 'Other', 'Prefer not to say'],31    default: ''32  },33  birthday: {34    type: String,35    default: ''36  },37  website: {38    type: String,39    default: ''40  },41  password: {42    type: String,43    minlength: [6, 'Password must be at least 6 characters long'],44    select: false // Don't return password in queries45  },46  avatar: {47    type: String,48    default: 'https://gravatar.com/avatar/00000000000000000000000000000000?d=mp&f=y'49  },50  bio: {51    type: String,52    maxlength: [500, 'Bio cannot exceed 500 characters'],53    default: ''54  },55  country: {56    type: String,57    default: ''58  },59  socialLinks: {60    github: String,61    linkedin: String,62    twitter: String63  },64  skills: [{65    type: String66  }],67  workExperience: [{68    company: String,69    position: String,70    duration: String71  }],72  education: [{73    school: String,74    degree: String,75    duration: String76  }],77  privacy: {78    showStats: {79      type: Boolean,80      default: true81    },82    showActivity: {83      type: Boolean,84      default: true85    }86  },87  profileViews: {88    type: Number,89    default: 090  },91  profileViewsLastWeek: {92    type: Number,93    default: 094  },95  reputation: {96    type: Number,97    default: 098  },99  reputationLastWeek: {100    type: Number,101    default: 0102  },103  solutionsPosted: {104    type: Number,105    default: 0106  },107  solutionsPostedLastWeek: {108    type: Number,109    default: 0110  },111  discussionsStarted: {112    type: Number,113    default: 0114  },115  discussionsStartedLastWeek: {116    type: Number,117    default: 0118  },119  badges: [{120    badgeId: String,121    badgeName: String,122    badgeDescription: String,123    badgeIcon: String,124    unlockedAt: {125      type: Date,126      default: Date.now127    }128  }],129  role: {130    type: String,131    enum: ['user'],132    default: 'user'133  },134  googleId: String,135  githubId: String,136  linkedinId: String,137  problemsSolved: {138    type: Number,139    default: 0140  },141  solvedProblems: [{142    type: mongoose.Schema.Types.ObjectId,143    ref: 'Problem'144  }],145  challengesSolved: {146    type: Number,147    default: 0148  },149  solvedChallengeProblems: [{150    challengeId: {151      type: mongoose.Schema.Types.ObjectId,152      ref: 'Challenge'153    },154    problemId: {155      type: mongoose.Schema.Types.ObjectId,156      ref: 'Problem'157    },158    solvedAt: {159      type: Date,160      default: Date.now161    }162  }],163  totalSubmissions: {164    type: Number,165    default: 0166  },167  streak: {168    type: Number,169    default: 0170  },171  status: {172    type: String,173    enum: ['online', 'offline', 'busy', 'away'],174    default: 'offline'175  },176  friends: [{177    user: {178      type: mongoose.Schema.Types.ObjectId,179      ref: 'User'180    },181    status: {182      type: String,183      enum: ['pending', 'accepted', 'rejected'],184      default: 'pending'185    },186    createdAt: {187      type: Date,188      default: Date.now189    }190  }],191  friendRequests: [{192    from: {193      type: mongoose.Schema.Types.ObjectId,194      ref: 'User'195    },196    token: { type: String },197    expiresAt: { type: Date },198    status: {199      type: String,200      enum: ['pending', 'accepted', 'rejected', 'expired'],201      default: 'pending'202    },203    createdAt: {204      type: Date,205      default: Date.now206    }207  }],208  lastActive: {209    type: Date,210    default: Date.now211  },212  inviteToken: {213    type: String,214    default: null215  },216  inviteTokenExpiry: {217    type: Date,218    default: null219  },220  resetPasswordOTP: {221    type: String,222    default: null223  },224  resetPasswordOTPExpiry: {225    type: Date,226    default: null227  },228  otpAttempts: {229    type: Number,230    default: 0231  },232  createdAt: {233    type: Date,234    default: Date.now235  }236});237 238// Encrypt password using bcrypt239UserSchema.pre('save', async function(next) {240  // Only hash the password if it's modified (or new)241  if (!this.isModified('password')) {242    return next();243  }244 245  // Only hash if password exists (for social logins, password might be empty)246  if (this.password) {247    const salt = await bcrypt.genSalt(10);248    this.password = await bcrypt.hash(this.password, salt);249  }250  next();251});252 253// Sign JWT and return254UserSchema.methods.getSignedJwtToken = function() {255  return jwt.sign({ id: this._id }, config.jwt.secret, {256    expiresIn: config.jwt.expire257  });258};259 260// Match user entered password to hashed password in database261UserSchema.methods.matchPassword = async function(enteredPassword) {262  return await bcrypt.compare(enteredPassword, this.password);263};264 265// Indexes for better query performance266UserSchema.index({ email: 1 }, { unique: true });267UserSchema.index({ username: 1 }, { unique: true });268UserSchema.index({ googleId: 1 }, { sparse: true });269UserSchema.index({ githubId: 1 }, { sparse: true });270UserSchema.index({ linkedinId: 1 }, { sparse: true });271UserSchema.index({ 'friends.user': 1 });272UserSchema.index({ 'friendRequests.from': 1 });273UserSchema.index({ lastActive: -1 });274UserSchema.index({ status: 1 });275UserSchema.index({ createdAt: -1 });276 277// CRITICAL: Index for leaderboard queries (most important!)278UserSchema.index({ problemsSolved: -1, totalSubmissions: 1 });279 280// Index for profile views tracking281UserSchema.index({ profileViews: -1 });282 283// Index for badge queries284UserSchema.index({ 'badges.badgeId': 1 });285 286// Compound index for search queries287UserSchema.index({ username: 'text', email: 'text' });288 289module.exports = mongoose.model('User', UserSchema);