import { compare, hash } from 'bcrypt'; import { Connection, Document, Model, Schema, SchemaTypes } from 'mongoose'; import { from, Observable } from 'rxjs'; import { RoleType } from '../shared/enum/role-type.enum'; interface User extends Document { comparePassword(password: string): Observable<boolean>; readonly username: string; readonly email: string; readonly password: string; readonly firstName?: string; readonly lastName?: string; readonly roles?: RoleType[]; } type UserModel = Model<User>; const UserSchema = new Schema<User>( { username: SchemaTypes.String, password: SchemaTypes.String, email: SchemaTypes.String, firstName: { type: SchemaTypes.String, required: false }, lastName: { type: SchemaTypes.String, required: false }, roles: [ { type: SchemaTypes.String, enum: ['ADMIN', 'USER'], required: false }, ], // use timestamps option to generate it automaticially. // createdAt: { type: SchemaTypes.Date, required: false }, // updatedAt: { type: SchemaTypes.Date, required: false }, }, { timestamps: true, toJSON: { virtuals: true, }, }, ); // see: https://wanago.io/2020/05/25/api-nestjs-authenticating-users-bcrypt-passport-jwt-cookies/ // and https://stackoverflow.com/questions/48023018/nodejs-bcrypt-async-mongoose-login async function preSaveHook(next) { // Only run this function if password was modified if (!this.isModified('password')) return next(); // Hash the password const password = await hash(this.password, 12); this.set('password', password); next(); } UserSchema.pre<User>('save', preSaveHook); function comparePasswordMethod(password: string): Observable<boolean> { return from(compare(password, this.password)); } UserSchema.methods.comparePassword = comparePasswordMethod; function nameGetHook() { return `${this.firstName} ${this.lastName}`; } UserSchema.virtual('name').get(nameGetHook); UserSchema.virtual('posts', { ref: 'Post', localField: '_id', foreignField: 'createdBy', }); const createUserModel: (conn: Connection) => UserModel = (conn: Connection) => conn.model<User>('User', UserSchema, 'users'); export { User, UserModel, createUserModel, UserSchema, preSaveHook, nameGetHook, comparePasswordMethod, };