'use strict'; const mongoose = require('mongoose'), Schema = mongoose.Schema, mongoUtil = require('../helpers/mongo'), Setting = require('./setting'), RptVar = require('./rpt_var'), Country = require('./country'), uniqid = require('uniqid'), { DEFAULT_LANG } = require('../helpers/constants'), { AppInputError } = require('../helpers/app_error'); const schema = new Schema({ /* The username is for uniquely identify a user and also used for sending mails to. For example: send user the password-reset email, sending reports, etc. */ username: { type: String, trim: true, index: { unique: true, partialFilterExpression: { username: { $type: 'string' } } }, set: v => (v === '' ? null : v) }, password: { type: String, trim: true, required: false, set: v => (v === '' ? null : v) }, name: { type: String, required: false }, address: { type: String, required: false }, phone: { type: String, required: false }, email: { type: String, required: false, unique: false }, active: { type: Boolean, default: true }, /* The preffered language from the available ones within the FE (English(en) - default, Spanish(es), Portuguese(pt)) */ lang: { type: String, default: DEFAULT_LANG }, parent: { type: Schema.Types.ObjectId, ref: 'User', required: false }, loggedInAt: { type: Date }, markedDelete: { type: Boolean, default: false }, // The migrated date for applicator and users paid before the migration to SM migratedDate: { type: Date, default: null }, needReview: { type: Boolean, default: false } }, { timestamps: true, discriminatorKey: 'kind', toJSON: { virtuals: true }, toObject: { virtuals: true }, strictQuery: false }); schema.virtual('Country', { ref: 'Country', localField: 'country', foreignField: 'code', justOne: true, }); class UserBaseSchema { static toUser(srcOjb) { if (!srcOjb) AppInputError.throw(); //throw new Error('Blank User is not supported !'); if (srcOjb['Country'] && typeof srcOjb['Country'] === 'object' && srcOjb['Country'].code) { srcOjb['country'] = srcOjb['Country'].code; } return srcOjb; } async markAsDeleted(session) { session && (session.startTransaction(mongoUtil.getTranOps())); try { // De-activate the username so same username can be re-used this.username && (this.username = this.username + '#' + uniqid()); this.active && (this.active = false); this.markedDelete = true; await this.save({ session }); } catch (error) { session && (session.abortTransaction()); throw error; } session && await mongoUtil.commitWithRetry(session); } async deleteMarked(session) { session && (session.startTransaction(mongoUtil.getTranOps())); try { await this.remove({ session }); } catch (error) { session && (session.abortTransaction()); throw error; } session && await mongoUtil.commitWithRetry(session); } } schema.loadClass(UserBaseSchema); async function clearRelatedData(doc) { if (!doc) return; await Setting.deleteMany({ userId: doc._id }).session(doc.$session()); await RptVar.deleteMany({ userId: doc._id }).session(doc.$session()); } /** * Handle pre-update hooks middleware before updating one user. */ schema.pre(['updateOne', 'findOneAndUpdate'], function () { // Convert ref objects to its code/id for storate if (this._update['Country'] && typeof this._update['Country'] === 'object' && this._update['Country'].code) { this._update['country'] = this._update['Country'].code; } }); schema.post('remove', async function () { await clearRelatedData(this); }); schema.post('findOneAndRemove', async function (doc) { await clearRelatedData(doc); }); schema.post('findOneAndDelete', async function (doc) { await clearRelatedData(doc); }); module.exports = mongoose.model('User', schema);