From: charleswrayjr Date: Fri, 12 Sep 2025 01:24:57 +0000 (-0500) Subject: Cleaning up the user model file. X-Git-Url: https://git.phasecustomsoft.com/static/git-favicon.png?a=commitdiff_plain;h=09c0a73cf3bb17cd9c531e4678f0612d97d80f77;p=phs-api.git Cleaning up the user model file. --- diff --git a/src/models/user.model.js b/src/models/user.model.js index e7c560e..5e3af78 100644 --- a/src/models/user.model.js +++ b/src/models/user.model.js @@ -1,8 +1,8 @@ /** - * @file User model for the users table + * @file User model for phase.users table */ -const { Model, ValidationError } = require('./model'); +const { Model, ValidationError } = require( './model' ); /** * @typedef {Object} User @@ -12,6 +12,7 @@ const { Model, ValidationError } = require('./model'); * @property {string} middle_name - User's middle name * @property {string} last_name - User's last name * @property {string|null} initials - User's initials + * @property {string|null} nickname - User's nickname (unique) * @property {number|null} created_by_id - ID of user who created this user * @property {Date} created_at - Creation timestamp * @property {boolean} is_deleted - Soft delete flag @@ -31,31 +32,53 @@ class User extends Model { * Create a User instance * @param {Partial} [props] - User properties */ - constructor(props) { - super(props); + constructor( props ) { + super( props ); this.table = 'phase.users'; this.prepend = 'u'; this.default_columns = [ - 'id', 'email', 'first_name', 'middle_name', 'last_name', 'initials', + 'id', 'email', 'first_name', 'middle_name', 'last_name', 'initials', 'nickname', 'created_by_id', 'created_at', 'is_deleted', 'deleted_by_id', 'deleted_at', 'is_active', 'deactivated_by_id', 'deactivated_at' ]; this.update_exclude_columns = ['id', 'created_at', 'is_deleted', 'deleted_at', 'deleted_by_id']; this.base_query = ` - SELECT u.id, u.email, u.first_name, u.middle_name, u.last_name, u.initials, - u.created_by_id, u.created_at, u.is_deleted, u.deleted_by_id, u.deleted_at, - u.is_active, u.deactivated_by_id, u.deactivated_at + SELECT u.id, + u.email, + u.first_name, + u.middle_name, + u.last_name, + u.initials, + u.nickname, + u.created_by_id, + u.created_at, + u.is_deleted, + u.deleted_by_id, + u.deleted_at, + u.is_active, + u.deactivated_by_id, + u.deactivated_at FROM phase.users u WHERE u.is_deleted = false `; this.base_list_query = ` - SELECT u.id, u.email, u.first_name, u.middle_name, u.last_name, u.initials, - u.created_by_id, u.created_at, u.is_active, u.deactivated_by_id, u.deactivated_at + SELECT u.id, + u.email, + u.first_name, + u.middle_name, + u.last_name, + u.initials, + u.nickname, + u.created_by_id, + u.created_at, + u.is_active, + u.deactivated_by_id, + u.deactivated_at FROM phase.users u WHERE u.is_deleted = false `; this.default_order_by = 'ORDER BY u.email ASC'; - this.instance = _props => new User(_props); + this.instance = _props => new User( _props ); } /** @@ -64,69 +87,27 @@ class User extends Model { * @returns {Promise} Created user instance * @throws {ValidationError} If required fields are missing */ - static async create(user_data) { + static async create( user_data ) { const { - email, first_name, middle_name = '', last_name, initials = null, + email, first_name, middle_name = '', last_name, initials = null, nickname = null, created_by_id = null, is_active = true, deactivated_by_id = null, deactivated_at = null } = user_data; if (!email || !first_name || !last_name) { - throw new ValidationError('Missing required fields: email, first_name, last_name'); + throw new ValidationError( 'Missing required fields: email, first_name, last_name' ); } const query_str = ` - INSERT INTO phase.users ( - email, first_name, middle_name, last_name, initials, created_by_id, - is_active, deactivated_by_id, deactivated_at - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *; + INSERT INTO phase.users (email, first_name, middle_name, last_name, initials, nickname, created_by_id, + is_active, deactivated_by_id, deactivated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + RETURNING *; `; const values = [ - email, first_name, middle_name, last_name, initials, created_by_id, - is_active, deactivated_by_id, deactivated_at + email, first_name, middle_name, last_name, initials, nickname, + created_by_id, is_active, deactivated_by_id, deactivated_at ]; - const result = await phsdb.query(query_str, values, { plain: true }); - if (!result) throw new ValidationError('Failed to create user'); - await this.createPhoneNumbers(); - await this.createAddresses(); - await this.createNickNames(); - return new User(result); - }; - - static async createPhoneNumbers( phone_numbers) { - if (phone_numbers?.length > 0) { - const pn = Array.from( new Set( phone_numbers ) ); - const phoneArray = []; - for (let phone_number of pn) { - const phone = await require('./phone_number.model').create(phone_number); - await phone.add_user(this.id) - .then( result => phoneArray.push(result) ) - .catch( err => throw new ValidationError( err.message ) ); - } - } else return true; - }; - - static async createAddresses( addresses) { - if (addresses?.length > 0) { - const addr = Array.from( new Set( addresses ) ); - const addrArray = []; - for (let address of addr) { - const _address = await require('./address.model').create(address); - await _address.add_user(this.id) - .then( result => addrArray.push(result) ) - .catch( err => throw new ValidationError( err.message ) ); - } - } else return true; - }; - - static async createNickNames( nicknames) { - if (nicknames?.length > 0) { - const names = Array.from( new Set( nicknames ) ); - const nameArray = []; - for (let name of names) { - const nickname = await require('./nickname.model').create(name); - await nickname.add_relation(this.id) - .then( result => nameArray.push(result) ) - .catch( err => throw new ValidationError( err.message ) ); - } - } else return true; + const result = await phsdb.query( query_str, values, { plain:true } ); + if (!result) throw new ValidationError( 'Failed to create user' ); + return new User( result ); }; /** @@ -135,8 +116,19 @@ class User extends Model { * @param {string[]} [excludes] - Fields to exclude from result * @returns {Promise} User instance or null */ - static async find_by_email(email, excludes = []) { - return await new User().find_one({ email }, excludes); + static async find_by_email( email, excludes = [] ) { + return await new User().find_one( { email }, excludes ); + } + + // noinspection JSUnusedGlobalSymbols + /** + * Find user by nickname + * @param {string} nickname - Nickname to search for + * @param {string[]} [excludes] - Fields to exclude from result + * @returns {Promise} User instance or null + */ + static async find_by_nickname( nickname, excludes = [] ) { + return await new User().find_one( { nickname }, excludes ); } /** @@ -147,9 +139,9 @@ class User extends Model { * @param {number} [offset=0] - Number of records to skip * @returns {Promise} Array of active users */ - static async find_active(excludes = [], order_by = null, limit = 100, offset = 0) { - return await new User().find_many({ is_active: true }, excludes, order_by, limit, offset); - } + static async find_active( excludes = [], order_by = null, limit = 100, offset = 0 ) { + return await new User().find_many( { is_active:true }, excludes, order_by, limit, offset ); + }; // noinspection JSUnusedGlobalSymbols /** @@ -160,25 +152,25 @@ class User extends Model { * @param {number} [offset=0] - Number of records to skip * @returns {Promise} Array of deleted users */ - static async find_deleted(excludes = [], order_by = null, limit = 100, offset = 0) { - const query_str = this.prototype.base_list_query.replace('WHERE u.is_deleted = false', 'WHERE u.is_deleted = true'); + static async find_deleted( excludes = [], order_by = null, limit = 100, offset = 0 ) { + const query_str = this.prototype.base_list_query.replace( 'WHERE u.is_deleted = false', 'WHERE u.is_deleted = true' ); const instance = this.prototype.instance; - const { keys, values } = this.prototype.build_where({}, this.prototype.default_columns); - values.push(limit, offset); + const { keys, values } = this.prototype.build_where( {}, this.prototype.default_columns ); + values.push( limit, offset ); const results = await phsdb.query( ` - ${query_str} - ${this.prototype.where_clause(keys, this.prototype.prepend)} - ${order_by ? `ORDER BY ${order_by.name} ${order_by.direction ?? 'asc'}` : this.prototype.default_order_by ?? ''} - LIMIT $${values.length - 1} OFFSET $${values.length} + ${ query_str } + ${ this.prototype.where_clause( keys, this.prototype.prepend ) } + ${ order_by ? `ORDER BY ${ order_by.name } ${ order_by.direction ?? 'asc' }` : this.prototype.default_order_by ?? '' } + LIMIT $${ values.length - 1 } OFFSET $${ values.length } `, values ); - return results.map(result => { - const found = instance(result); - excludes?.forEach(e => delete found[e]); + return results.map( result => { + const found = instance( result ); + excludes?.forEach( e => delete found[e] ); return found; - }); + } ); } /** @@ -187,16 +179,16 @@ class User extends Model { * @returns {Promise} Updated user instance * @throws {ValidationError} If deactivated_by_id is invalid */ - async deactivate(deactivated_by_id) { - const deactivated_by_id_int = parseInt(deactivated_by_id, 10); - if (isNaN(deactivated_by_id_int)) { - throw new ValidationError('deactivated_by_id must be a valid integer'); + async deactivate( deactivated_by_id ) { + const deactivated_by_id_int = parseInt( deactivated_by_id, 10 ); + if (isNaN( deactivated_by_id_int )) { + throw new ValidationError( 'deactivated_by_id must be a valid integer' ); } - return await this.update({ - is_active: false, - deactivated_at: new Date().toISOString(), - deactivated_by_id: deactivated_by_id_int - }); + return await this.update( { + is_active:false, + deactivated_at:new Date().toISOString(), + deactivated_by_id:deactivated_by_id_int + } ); } /** @@ -204,11 +196,11 @@ class User extends Model { * @returns {Promise} Updated user instance */ async reactivate() { - return await this.update({ - is_active: true, - deactivated_at: null, - deactivated_by_id: null - }); + return await this.update( { + is_active:true, + deactivated_at:null, + deactivated_by_id:null + } ); } /** @@ -217,16 +209,16 @@ class User extends Model { * @returns {Promise} Updated user instance * @throws {ValidationError} If deleted_by_id is invalid */ - async soft_delete(deleted_by_id) { - const deleted_by_id_int = parseInt(deleted_by_id, 10); - if (isNaN(deleted_by_id_int)) { - throw new ValidationError('deleted_by_id must be a valid integer'); + async soft_delete( deleted_by_id ) { + const deleted_by_id_int = parseInt( deleted_by_id, 10 ); + if (isNaN( deleted_by_id_int )) { + throw new ValidationError( 'deleted_by_id must be a valid integer' ); } - return await this.update({ - is_deleted: true, - deleted_at: new Date().toISOString(), - deleted_by_id: deleted_by_id_int - }); + return await this.update( { + is_deleted:true, + deleted_at:new Date().toISOString(), + deleted_by_id:deleted_by_id_int + } ); } /** @@ -237,16 +229,6 @@ class User extends Model { return this.is_active === true; } - // noinspection JSUnusedGlobalSymbols - /** - * Get the user who created this user - * @returns {Promise} Creator user instance or null - */ - async get_created_by() { - if (!this.created_by_id) return null; - return await new User().find_one({ id: this.created_by_id }, []); - } - // noinspection JSUnusedGlobalSymbols /** * Get user data without sensitive information