'use strict'; import mongoose from 'mongoose'; import passportLocalMongoose from 'passport-local-mongoose'; const AdminActionSchema = new mongoose.Schema({ _id: {type: String, required: true}, name: {type: String, required: true}, paths: [{ method: String, path: String, }], deleted: {type: Boolean, default: false}, deleted_time: {type: Date}, }, { collection: 'admin_actions', timestamps: true, }); const AdminAction = mongoose.model('AdminAction', AdminActionSchema); const AdminRoleSchema = new mongoose.Schema({ _id: {type: String, required: true}, name: {type: String, required: true}, permissions: [{type: String, ref: 'AdminAction'}], deleted: {type: Boolean, default: false}, deleted_time: {type: Date}, }, { collection: 'admin_roles', timestamps: true, }); const AdminRole = mongoose.model('AdminRole', AdminRoleSchema); /** * 用户表不需要添加 timestamps: true * * 因为 createdAt 可以从ObjectID中提取, updatedAt 会因为last和ateemps随时变更, * 如果需要跟踪关键数据的变更时间, 应添加独立自管的 updatedAt, * 或者直接使用 immutable data 追踪变化 */ const AdminSchema = new mongoose.Schema({ username: String, password: String, roles: [{type: String, ref: 'AdminRole'}], permissions: [{type: String, ref: 'AdminAction'}], games: [{type: String}], profile: { name: String, gender: String, }, comment: String, createdBy: {type: String, ref: 'Admin', required: true}, lastModifiedBy: {type: String, ref: 'Admin', required: true}, locked: {type: Boolean, default: false}, locked_time: {type: Date}, deleted: {type: Boolean, default: false}, delete_time: {type: Date}, lastLogin: Date, // passport-local-mongoose 添加的 last 字段记录的是最后一次登录尝试, // 而不是最后一次成功登录 }); AdminSchema.virtual('createdAt').get(function() { return this._id.getTimestamp(); }); /** * TODO this is far away from elegant, maybe change it later. */ AdminSchema.virtual('hasSysAdmin').get(function() { return this.roles.includes('sys_admin'); }); AdminSchema.virtual('hasNavSystem').get(function() { let yes = this.roles.includes('admin'); yes = yes || this.permissions.includes('edit_accounts'); return yes; }); AdminSchema.virtual('hasNavGameApi').get(function() { let yes = this.roles.includes('admin'); yes = yes || this.roles.includes('game_api_manager'); yes = yes || this.permissions.includes('edit_game_apis'); return yes; }); AdminSchema.virtual('hasNavRedis').get(function() { let yes = this.roles.includes('admin'); yes = yes || this.roles.includes('redis_manager'); yes = yes || this.permissions.includes('edit_redis'); return yes; }); AdminSchema.virtual('hasNavWechat').get(function() { let yes = this.roles.includes('admin'); yes = yes || this.roles.includes('wechat_manager'); yes = yes || this.permissions.includes('edit_wechat'); return yes; }); AdminSchema.virtual('hasNavGM').get(function() { let yes = this.roles.includes('admin'); yes = yes || this.roles.includes('gm_manager'); yes = yes || this.permissions.includes('edit_gm'); return yes; }); AdminSchema.virtual('hasNavTool').get(function() { let yes = this.roles.includes('admin'); yes = yes || this.roles.includes('tool_manager'); yes = yes || this.permissions.includes('edit_tool'); return yes; }); AdminSchema.virtual('hasAdminRole').get(function() { return this.roles.includes('admin'); }); AdminSchema.methods.checkGame = function(gid) { let yes = this.roles.includes('admin'); yes = yes || this.games.includes(gid); return yes; }; AdminSchema.plugin(passportLocalMongoose, { limitAttempts: true, usernameLowerCase: true, maxAttempts: 10, errorMessages: { MissingPasswordError: '请输入密码', AttemptTooSoonError: '您的账户当前被锁定,请稍后再试', TooManyAttemptsError: '您的账户因错误登录次数太多而被锁定', NoSaltValueStoredError: 'Authentication not possible. No salt value stored', IncorrectPasswordError: '用户名或密码错误', IncorrectUsernameError: '用户名或密码错误', MissingUsernameError: '请输入用户名', UserExistsError: '您输入的用户名已被使用', }, }); const Admin = mongoose.model('Admin', AdminSchema); export {Admin, AdminRole, AdminAction};