import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common'; import { CreateClientLoginsDTO, CreateSPLoginsDTO, CreateUSCIBLoginsDTO, EMAIL_DTO, GetCarnetDetailsbyCarnetStatusDTO, SPID_CLIENTID_DTO, SPID_DTO, SPID_EMAIL_DTO, USERID_DTO } from 'src/dto/property.dto'; import { checkPgUserDefinedErrors, extractSubdomain, handlePgError, normalizeKeysToUpperCase, releasePgClient, ResponseStatus, toUpperCaseKeys } from 'src/utils/helper'; import { PoolClient } from 'pg'; import { PgDBService } from 'src/db/db.service'; import { InternalServerException } from 'src/exceptions/internalServerError.exception'; import { AuthService } from 'src/auth/auth.service'; import { MailTypeDTO } from 'src/auth/auth.dto'; import { Request } from 'express'; @Injectable() export class UserMaintenanceService { private readonly logger = new Logger(UserMaintenanceService.name); constructor( private readonly pgDBService: PgDBService, @Inject(forwardRef(() => AuthService)) private readonly authService: AuthService ) { } async GetSPUserDetails(body: USERID_DTO): Promise { let client: PoolClient | null = null; // Assign unique names to each cursor const roleCursor = 'role_cursor'; const menuCursor = 'menu_cursor'; const menuPageCursor = 'menu_page_cursor'; const userDetailsCursor = 'user_details_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".spclientuser_pkg_getspuserdetails($1, $2, $3, $4, $5) `; await client.query(callProcQuery, [ body.P_USERID, roleCursor, menuCursor, menuPageCursor, userDetailsCursor ]); // Fetch all data from each cursor const roleResult = await client.query(`FETCH ALL FROM ${roleCursor}`); const menuResult = await client.query(`FETCH ALL FROM ${menuCursor}`); const menuPageResult = await client.query(`FETCH ALL FROM ${menuPageCursor}`); const userDetailsResult = await client.query(`FETCH ALL FROM ${userDetailsCursor}`); // Close all cursors await client.query(`CLOSE ${roleCursor}`); await client.query(`CLOSE ${menuCursor}`); await client.query(`CLOSE ${menuPageCursor}`); await client.query(`CLOSE ${userDetailsCursor}`); await client.query('COMMIT'); // no need for this api // checkPgUserDefinedErrors(roleResult); // checkPgUserDefinedErrors(menuResult); // checkPgUserDefinedErrors(menuPageResult); // checkPgUserDefinedErrors(userDetailsResult); return { roleDetails: toUpperCaseKeys(roleResult.rows).map(x => x.ROLENAME), menuDetails: toUpperCaseKeys(menuResult.rows).map(x => x.MENUNAME), menuPageDetails: toUpperCaseKeys(menuPageResult.rows), userDetails: toUpperCaseKeys(userDetailsResult.rows)[0], }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, 'getSpUserDetails'); } finally { releasePgClient(client); } } async LockUserAccount(body: SPID_EMAIL_DTO) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_lockuseraccount($1, $2, $3) `; await client.query(callProcQuery, [ body.P_SPID, body.P_EMAILADDR, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); // return { // statusCode: 201, // message: ResponseStatus.lockedUserDone, // ...toUpperCaseKeys(fetchResult?.rows)[0] // }; return toUpperCaseKeys(fetchResult?.rows) } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } // USCIB_LOGINS async GetUSCIBLogins() { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_getusciblogins($1) `; await client.query(callProcQuery, [cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } async CreateUSCIBLogins(body: CreateUSCIBLoginsDTO, req: Request) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_createusciblogins($1, $2, $3, $4, $5) `; await client.query(callProcQuery, [ body.P_USERID, body.P_EMAILADDR, body.P_LOOKUPCODE, body.P_ENABLEPASSWORDPOLICY, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); let appDomain; if (req.headers.origin) { appDomain = extractSubdomain(req.headers.origin) } else { appDomain = "" } const mailRes = await this.authService.sendMail({ P_TO: body.P_USERID, P_MAIL_TYPE: MailTypeDTO.REGISTER_USCIB }, appDomain) if (mailRes.statusCode !== 200) { throw new InternalServerException(); } return { statusCode: 201, message: ResponseStatus.created, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } // SP LOGINS async GetSPLogins(body: SPID_DTO) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_getsplogins($1, $2) `; await client.query(callProcQuery, [body.P_SPID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } async CreateSPLogins(body: CreateSPLoginsDTO, req: Request) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_createsplogins($1, $2, $3, $4, $5, $6, $7) `; await client.query(callProcQuery, [ body.P_SPID, body.P_USERID, body.P_DOMAIN, body.P_EMAILADDR, body.P_LOOKUPCODE, body.P_ENABLEPASSWORDPOLICY, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); let appDomain; if (req.headers.origin) { appDomain = extractSubdomain(req.headers.origin) } else { appDomain = "" } const mailRes = await this.authService.sendMail({ P_TO: body.P_USERID, P_MAIL_TYPE: MailTypeDTO.REGISTER_SP }, appDomain) if (mailRes.statusCode !== 200) { throw new InternalServerException(); } return { statusCode: 201, message: ResponseStatus.created, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } // CLIENT LOGINS async GetClientloginsBySPID(body: SPID_DTO) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_getclientloginsbyspid($1, $2) `; await client.query(callProcQuery, [body.P_SPID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } async GetClientloginsByClientID(body: SPID_CLIENTID_DTO) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_getclientloginsbyclientid($1, $2, $3) `; await client.query(callProcQuery, [body.P_SPID, body.P_CLIENTID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); return toUpperCaseKeys(fetchResult.rows); } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } async CreateClientLogins(body: CreateClientLoginsDTO, req: Request) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_createclientlogins($1, $2, $3, $4, $5) `; await client.query(callProcQuery, [ body.P_SPID, body.P_USERID, body.P_CLIENTCONTACTID, body.P_ENABLEPASSWORDPOLICY, cursorName ]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); let appDomain; if (req.headers.origin) { appDomain = extractSubdomain(req.headers.origin) } else { appDomain = "" } const mailRes = await this.authService.sendMail({ P_TO: body.P_USERID, P_MAIL_TYPE: MailTypeDTO.REGISTER_CLIENT }, appDomain) if (mailRes.statusCode !== 200) { throw new InternalServerException(); } return { statusCode: 201, message: ResponseStatus.clientRegistrationDone, ...toUpperCaseKeys(fetchResult?.rows)[0] }; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } // validate email async ValidateEmail(body: EMAIL_DTO) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_validateemail($1, $2) `; await client.query(callProcQuery, [body.P_EMAILADDR, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); if (fetchResult?.rows.length > 0) { return toUpperCaseKeys(fetchResult.rows) } else { return []; } } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } //carnet summary data async GetCarnetSummaryData(body: USERID_DTO) { let client: PoolClient | null = null; const cursorName = 'p_cursor'; try { client = await this.pgDBService.getConnection(); await client.query('BEGIN'); const callProcQuery = ` CALL "CARNETSYS".userlogin_pkg_getcarnetsummarydata($1, $2) `; await client.query(callProcQuery, [body.P_USERID, cursorName]); // 🚫 DON'T quote the cursor name in FETCH const fetchResult = await client.query(`FETCH ALL FROM ${cursorName}`); // 🚫 DON'T quote the cursor name in CLOSE await client.query(`CLOSE ${cursorName}`); await client.query('COMMIT'); checkPgUserDefinedErrors(fetchResult); const fres: any = toUpperCaseKeys(fetchResult.rows); // Step 1: Replace spaces in keys const mappedRows = fres.map((obj) => { const newObj = {}; for (const key in obj) { const newKey = key.replace(/ /g, '_'); newObj[newKey] = obj[key]; } return newObj; }); // Step 2: Group and aggregate const reducedRows = mappedRows.reduce((acc, curr) => { let existing; if (curr.SERVICE_PROVIDER_NAME && curr.SPID) { existing = acc.find( (item) => item.SERVICE_PROVIDER_NAME === curr.SERVICE_PROVIDER_NAME && item.SPID === curr.SPID ); } else if (curr.PREPARER_NAME && curr.CLIENTID) { existing = acc.find( (item) => item.PREPARER_NAME === curr.PREPARER_NAME && item.CLIENTID === curr.CLIENTID ); } if (existing) { existing.CARNETSTATUS.push(curr.CARNETSTATUS); existing.CARNET_COUNT.push(curr.CARNET_COUNT); } else { const newItem = { CARNETSTATUS: [curr.CARNETSTATUS], Carnet_Count: [curr.CARNET_COUNT], }; if (curr.SERVICE_PROVIDER_NAME && curr.SPID) { newItem['SERVICE_PROVIDER_NAME'] = curr.SERVICE_PROVIDER_NAME; newItem['SPID'] = curr.SPID; } else if (curr.PREPARER_NAME && curr.CLIENTID) { newItem['PREPARER_NAME'] = curr.PREPARER_NAME; newItem['CLIENTID'] = curr.CLIENTID; } acc.push(newItem); } return acc; }, []); return reducedRows; } catch (error) { if (client) await client.query('ROLLBACK'); handlePgError(error, UserMaintenanceService.name) } finally { releasePgClient(client) } } }