import { Injectable, Logger } from '@nestjs/common'; import { OracleDBService } from 'src/db/db.service'; import { CreateUSCIBLoginsDTO, GetSPUserDetailsDTO, UseSPIDDTO } from './user-maintenance.dto'; import { InternalServerException } from 'src/exceptions/internalServerError.exception'; import * as oracledb from 'oracledb'; import { BadRequestException } from 'src/exceptions/badRequest.exception'; interface RoleDetail { [key: string]: any; } interface MenuDetail { [key: string]: any; } interface MenuPageDetail { [key: string]: any; } interface UserDetail { [key: string]: any; } export interface GetUserDetailsResult { roleDetails: RoleDetail[]; menuDetails: MenuDetail[]; menuPageDetails: MenuPageDetail[]; userDetails: UserDetail[]; } @Injectable() export class UserMaintenanceService { private readonly logger = new Logger(UserMaintenanceService.name); constructor(private readonly oracleDBService: OracleDBService) { } private async fetchCursor(cursor: oracledb.ResultSet): Promise { try { const rows = await cursor.getRows(); // or getRows(1000) if needed await cursor.close(); return rows; } catch (err) { this.logger.error('Failed to fetch from cursor', err.stack || err); throw new InternalServerException("Error reading data from database."); } } async GetSPUserDetails(body: GetSPUserDetailsDTO): Promise { let connection; try { connection = await this.oracleDBService.getConnection(); const result = await connection.execute( `BEGIN SPCLIENTUSER_PKG.GetSPUserDetails( :P_USERID, :P_ROLECUR, :P_MENUCUR, :P_MENUPAGECUR, :P_USERDETAILS ); END;`, { P_USERID: { val: body.p_userid, type: oracledb.DB_TYPE_NVARCHAR }, P_ROLECUR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, P_MENUCUR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, P_MENUPAGECUR: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, P_USERDETAILS: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, }, { outFormat: oracledb.OUT_FORMAT_OBJECT } ); const outBinds = result.outBinds; if (!outBinds?.P_ROLECUR || !outBinds?.P_MENUCUR || !outBinds?.P_MENUPAGECUR || !outBinds?.P_USERDETAILS) { this.logger.error('One or more expected cursors are missing from stored procedure output.'); throw new InternalServerException("Incomplete data received from the database."); } let userdetailsTemp: any = await this.fetchCursor(outBinds.P_USERDETAILS); return { roleDetails: await this.fetchCursor(outBinds.P_ROLECUR), menuDetails: await this.fetchCursor(outBinds.P_MENUCUR), menuPageDetails: await this.fetchCursor(outBinds.P_MENUPAGECUR), userDetails: userdetailsTemp[0] }; } catch (error) { if (error instanceof BadRequestException) { this.logger.warn(error.message); throw error; } else if (error.message.includes("NJS-107")) { this.logger.warn("Invalid cursor encountered: " + error.message); throw new BadRequestException("Invalid database response."); } else if (error.message.includes("ORA-")) { this.logger.error("Oracle error occurred: " + error.message); throw new InternalServerException(error.message); } this.logger.error('GetSPUserDetails failed', error.stack || error); throw new InternalServerException(error.message); } finally { if (connection) { try { await connection.close(); } catch (closeErr) { this.logger.error('Failed to close DB connection', closeErr); } } } } async GetSPUserDetailsv1(body: GetSPUserDetailsDTO): Promise { let connection; try { connection = await this.oracleDBService.getConnection(); const result = await connection.execute( `BEGIN SPCLIENTUSER_PKG.GetSPUserDetails( :p_userid , :p_rolecur , :p_menucur , :p_menuPageCur , :p_userdetails ); END;`, { p_userid: { val: body.p_userid, type: oracledb.DB_TYPE_NVARCHAR }, p_rolecur: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, p_menucur: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, p_menuPageCur: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, p_userdetails: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }, }, { outFormat: oracledb.OUT_FORMAT_OBJECT } ); const outBinds = result.outBinds; if (!outBinds?.p_rolecur || !outBinds?.p_menucur || !outBinds?.p_menuPageCur || !outBinds?.p_userdetails) { this.logger.error('One or more expected cursors are missing from stored procedure output.'); throw new InternalServerException("Incomplete data received from the database."); } return { roleDetails: await this.fetchCursor(outBinds.p_rolecur), menuDetails: await this.fetchCursor(outBinds.p_menucur), menuPageDetails: await this.fetchCursor(outBinds.p_menuPageCur), userDetails: await this.fetchCursor(outBinds.p_userdetails), }; } catch (error) { if (error instanceof BadRequestException) { this.logger.warn(error.message); throw error; } else if (error.message.includes("NJS-107")) { this.logger.warn("Invalid cursor encountered: " + error.message); throw new BadRequestException("Invalid database response."); } else if (error.message.includes("ORA-")) { this.logger.error("Oracle error occurred: " + error.message); throw new InternalServerException(error.message); } this.logger.error('GetSPUserDetails failed', error.stack || error); throw new InternalServerException(error.message); } finally { if (connection) { try { await connection.close(); } catch (closeErr) { this.logger.error('Failed to close DB connection', closeErr); } } } } async CreateUSCIBLogins(body: CreateUSCIBLoginsDTO) { let connection; try { connection = await this.oracleDBService.getConnection(); const result = await connection.execute( `BEGIN Userlogin_pkg.CreateUSCIBLogins( :p_userid , :p_emailaddr , :p_lookupCode , :p_password , :P_EnablePasswordPolicy, :p_cursor ); END;`, { p_userid: { val: body.p_userid, type: oracledb.DB_TYPE_NVARCHAR }, p_emailaddr: { val: body.p_emailaddr, type: oracledb.DB_TYPE_NVARCHAR }, p_lookupCode: { val: body.p_lookupCode, type: oracledb.DB_TYPE_NVARCHAR }, p_password: { val: body.p_password, type: oracledb.DB_TYPE_NVARCHAR }, P_EnablePasswordPolicy: { val: body.P_EnablePasswordPolicy, type: oracledb.DB_TYPE_NVARCHAR }, p_cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, { outFormat: oracledb.OUT_FORMAT_OBJECT } ); const outBinds = result.outBinds; if (!outBinds?.p_cursor) { this.logger.error('One or more expected cursors are missing from stored procedure output.'); throw new InternalServerException("Incomplete data received from the database."); } return { data: await this.fetchCursor(outBinds.p_cursor), }; } catch (error) { if (error instanceof BadRequestException) { this.logger.warn(error.message); throw error; } else if (error.message.includes("NJS-107")) { this.logger.warn("Invalid cursor encountered: " + error.message); throw new BadRequestException("Invalid database response."); } else if (error.message.includes("ORA-")) { this.logger.error("Oracle error occurred: " + error.message); throw new InternalServerException(error.message); } this.logger.error('GetSPUserDetails failed', error.stack || error); throw new InternalServerException(error.message); } finally { if (connection) { try { await connection.close(); } catch (closeErr) { this.logger.error('Failed to close DB connection', closeErr); } } } } async GetUSCIBLogins() { let connection; try { connection = await this.oracleDBService.getConnection(); const result = await connection.execute( `BEGIN Userlogin_pkg.GetUSCIBLogins( :p_cursor ); END;`, { p_cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, { outFormat: oracledb.OUT_FORMAT_OBJECT } ); const outBinds = result.outBinds; if (!outBinds?.p_cursor) { this.logger.error('One or more expected cursors are missing from stored procedure output.'); throw new InternalServerException("Incomplete data received from the database."); } return await this.fetchCursor(outBinds.p_cursor); } catch (error) { if (error instanceof BadRequestException) { this.logger.warn(error.message); throw error; } else if (error.message.includes("NJS-107")) { this.logger.warn("Invalid cursor encountered: " + error.message); throw new BadRequestException("Invalid database response."); } else if (error.message.includes("ORA-")) { this.logger.error("Oracle error occurred: " + error.message); throw new InternalServerException(error.message); } this.logger.error('GetSPUserDetails failed', error.stack || error); throw new InternalServerException(error.message); } finally { if (connection) { try { await connection.close(); } catch (closeErr) { this.logger.error('Failed to close DB connection', closeErr); } } } } async GetSPLogins(body: UseSPIDDTO) { let connection; try { connection = await this.oracleDBService.getConnection(); const result = await connection.execute( `BEGIN Userlogin_pkg.GetSPLogins( :p_spid , :p_cursor ); END;`, { p_spid: { val: body.p_spid, type: oracledb.DB_TYPE_NUMBER }, p_cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT } }, { outFormat: oracledb.OUT_FORMAT_OBJECT } ); const outBinds = result.outBinds; if (!outBinds?.p_cursor) { this.logger.error('One or more expected cursors are missing from stored procedure output.'); throw new InternalServerException("Incomplete data received from the database."); } return await this.fetchCursor(outBinds.p_cursor); } catch (error) { if (error instanceof BadRequestException) { this.logger.warn(error.message); throw error; } else if (error.message.includes("NJS-107")) { this.logger.warn("Invalid cursor encountered: " + error.message); throw new BadRequestException("Invalid database response."); } else if (error.message.includes("ORA-")) { this.logger.error("Oracle error occurred: " + error.message); throw new InternalServerException(error.message); } this.logger.error('GetSPUserDetails failed', error.stack || error); throw new InternalServerException(error.message); } finally { if (connection) { try { await connection.close(); } catch (closeErr) { this.logger.error('Failed to close DB connection', closeErr); } } } } }