From 2be501ed4327db2f52a9d73583110e2685eefaa5 Mon Sep 17 00:00:00 2001 From: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:19:13 +0530 Subject: [PATCH] Feat : added user mapping for multiple boundaries with common parent (#1005) --- .../src/server/config/index.ts | 5 +- .../src/server/utils/campaignMappingUtils.ts | 116 +++++++++++++++--- 2 files changed, 104 insertions(+), 17 deletions(-) diff --git a/utilities/project-factory/src/server/config/index.ts b/utilities/project-factory/src/server/config/index.ts index 50fe8b45453..2f5dbe4ede4 100644 --- a/utilities/project-factory/src/server/config/index.ts +++ b/utilities/project-factory/src/server/config/index.ts @@ -16,8 +16,8 @@ const getDBSchemaName = (dbSchema = "") => { } // Configuration object containing various environment variables const config = { - excludeHierarchyTypeFromBoundaryCodes:false, - excludeBoundaryNameAtLastFromBoundaryCodes:false, + excludeHierarchyTypeFromBoundaryCodes: false, + excludeBoundaryNameAtLastFromBoundaryCodes: false, masterNameForSchemaOfColumnHeaders: "adminSchema", masterNameForSplitBoundariesOn: "hierarchyConfig", boundary: { @@ -38,6 +38,7 @@ const config = { userSchemaMasterName: process.env.USER_SCHEMA_MASTER || "userSchema", userDefaultPassword: process.env.USER_DEFAULT_PASSWORD || "eGov@123", userPasswordAutoGenerate: process.env.USER_PASSWORD_AUTO_GENERATE || "true", + mapUserViaCommonParent: process.env.MAP_USER_VIA_COMMON_PARENT || false, }, cacheValues: { cacheEnabled: process.env.CACHE_ENABLED, diff --git a/utilities/project-factory/src/server/utils/campaignMappingUtils.ts b/utilities/project-factory/src/server/utils/campaignMappingUtils.ts index f4905eaeb41..4f70d496543 100644 --- a/utilities/project-factory/src/server/utils/campaignMappingUtils.ts +++ b/utilities/project-factory/src/server/utils/campaignMappingUtils.ts @@ -2,7 +2,7 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; import { getDataFromSheet, throwError } from "./genericUtils"; import { getFormattedStringForDebug, logger } from "./logger"; -import { httpRequest } from "./request"; +import { defaultheader, httpRequest } from "./request"; import { produceModifiedMessages } from "../kafka/Listener"; import { getLocalizedName } from "./campaignUtils"; import { campaignStatuses, resourceDataStatuses } from "../config/constants"; @@ -36,8 +36,107 @@ function getPvarIds(messageObject: any) { return Array.from(uniquePvarIds); // Convert Set to array before returning } +function trimBoundaryCodes(root: any) { + if (root) { + root.code = root.code.trim(); // Trim the code + + // Recursively trim the codes in the children + for (const child of root.children) { + trimBoundaryCodes(child); + } + } +} + +async function getAllBoundaries(messageObject: any, tenantId: any, rootBoundary: any, hierarchyType: any) { + const BoundarySearchBody = { + RequestInfo: messageObject?.RequestInfo, + } + const params = { + tenantId, + codes: rootBoundary, + hierarchyType, + includeChildren: true + } + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, BoundarySearchBody, params, undefined, undefined, header); + trimBoundaryCodes(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]); + return boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0] +} + +// Function to find the path to a given boundary code +function findPath(root: any, code: string, path: any[] = []) { + if (root.code === code) { + return [...path, root]; + } + for (const child of root.children) { + const result: any = findPath(child, code, [...path, root]); + if (result) return result; + } + return null; +} + +// Function to find the common parent for multiple codes +function findCommonParent(codes: string[], root: any) { + if (codes.length === 0) return null; + + // Find paths for all codes + const paths = codes.map(code => findPath(root, code)).filter(path => path !== null); + + if (paths.length === 0) return null; + + // Compare paths to find the common ancestor + let commonParent: any = null; + + for (let i = 0; i < Math.min(...paths.map(path => path.length)); i++) { + const currentParent = paths[0][i]; + if (paths.every(path => path[i] && path[i].code === currentParent.code)) { + commonParent = currentParent; + } else { + break; + } + } + + return commonParent?.code; +} + +function mapBoundaryCodes(resource: any, code: string, boundaryCode: string, boundaryCodes: any, allBoundaries: any) { + // Split boundary codes if they have comma separated values + const boundaryCodesArray = boundaryCode.split(',').map((bc: string) => bc.trim()); + if (resource?.type == "user" && boundaryCodesArray?.length > 1 && config.user.mapUserViaCommonParent) { + const commonParent = findCommonParent(boundaryCodesArray, allBoundaries); + if (commonParent) { + logger.info(`Boundary Codes Array ${boundaryCodesArray.join(",")} for resource ${resource?.type} has common parent ${commonParent}`) + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][commonParent]) { + boundaryCodes[resource?.type][commonParent] = []; + } + boundaryCodes[resource?.type][commonParent].push(code); + logger.info(`Common Parent Boundary code ${commonParent} mapped to resource ${resource?.type} with code ${code}`) + } + } + else { + boundaryCodesArray.forEach((trimmedBC: string) => { + // Trim any leading or trailing spaces + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][trimmedBC]) { + boundaryCodes[resource?.type][trimmedBC] = []; + } + boundaryCodes[resource?.type][trimmedBC].push(code); + logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) + }); + } +} + async function enrichBoundaryCodes(resources: any[], messageObject: any, boundaryCodes: any, sheetName: any) { const localizationMap: any = messageObject?.localizationMap + const allBoundaries = await getAllBoundaries(messageObject, messageObject?.Campaign?.tenantId, messageObject?.Campaign?.boundaryCode, messageObject?.Campaign?.hierarchyType); for (const resource of resources) { const processedFilestoreId = resource?.processedFilestoreId; if (processedFilestoreId) { @@ -54,20 +153,7 @@ async function enrichBoundaryCodes(resources: any[], messageObject: any, boundar active = data[activeColumn]; } if (boundaryCode && active == "Active") { - // Split boundary codes if they have comma separated values - const boundaryCodesArray = boundaryCode.split(','); - boundaryCodesArray.forEach((bc: string) => { - // Trim any leading or trailing spaces - const trimmedBC = bc.trim(); - if (!boundaryCodes[resource?.type]) { - boundaryCodes[resource?.type] = {}; - } - if (!boundaryCodes[resource?.type][trimmedBC]) { - boundaryCodes[resource?.type][trimmedBC] = []; - } - boundaryCodes[resource?.type][trimmedBC].push(code); - logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) - }); + mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); } } else {