From 7e3b9bc2807d773b80457a6796daa3b5909eb78a Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Mon, 13 Oct 2025 11:25:45 +0530 Subject: [PATCH 1/5] @coderabbitai --- src/helpers/userInvite.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/userInvite.js b/src/helpers/userInvite.js index 81e7526b2..a12bb2b5e 100644 --- a/src/helpers/userInvite.js +++ b/src/helpers/userInvite.js @@ -916,6 +916,8 @@ module.exports = class UserInviteHelper { username: userUpdate[0].dataValues?.username, status: userUpdate[0].dataValues?.status, deleted: userUpdate[0].dataValues?.deleted_at ? true : false, + tenant_code: user.tenant_code, + organization_code: user.organization_code, created_at: userUpdate[0].dataValues?.created_at || null, updated_at: userUpdate[0].dataValues?.updated_at || new Date(), oldValues, From 7dd11b33a40b204ca9a8dfcff90c26c72ffd9b52 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Wed, 15 Oct 2025 19:53:31 +0530 Subject: [PATCH 2/5] Event issue fixed --- src/helpers/userInvite.js | 68 +++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/helpers/userInvite.js b/src/helpers/userInvite.js index a12bb2b5e..162282356 100644 --- a/src/helpers/userInvite.js +++ b/src/helpers/userInvite.js @@ -841,29 +841,28 @@ module.exports = class UserInviteHelper { let oldValues = {}, newValues = {}, - userFetch = {} + userFetch = + isOrgUpdate || + isRoleUpdated || + modifiedKeys.length > 0 || + additionalCsvHeaders.length > 0 + ? await userQueries.findAllUserWithOrganization( + { id: existingUser.id }, + {}, + user.tenant_code + ) + : {} + + userFetch = userFetch?.[0] || {} + if (isOrgUpdate || isRoleUpdated) { oldValues.organizations = existingUser.organizations - userFetch = await userQueries.findAllUserWithOrganization( - { id: existingUser.id }, - {}, - user.tenant_code - ) - - newValues.organizations = userFetch[0].organizations + newValues.organizations = userFetch.organizations } + let userMeta = {} if (modifiedKeys.length > 0 || additionalCsvHeaders.length > 0) { - if (Object.keys(userFetch).length == 0) { - userFetch = await userQueries.findAllUserWithOrganization( - { id: existingUser.id }, - {}, - user.tenant_code - ) - } - - userFetch = userCredentials.find((user) => user.id == existingUser.id) - let userMeta = { ...userFetch?.meta } + userMeta = { ...userFetch?.meta } userFetch = await utils.processDbResponse(userFetch, prunedEntities) const comparisonKeys = [...modifiedKeys, ...additionalCsvHeaders] comparisonKeys.forEach((modifiedKey) => { @@ -888,24 +887,30 @@ module.exports = class UserInviteHelper { } }) - oldValues = userFetch - oldValues.email = oldValues.email - ? emailEncryption.decrypt(oldValues.email) - : oldValues.email /* user meta with entity and _id from external micro-service is passed with entity information and value of the _ids to prarse it to a standard format with data for emitting the event */ userMeta = utils.parseMetaData(userMeta, prunedEntities, externalEntityNameIdMap) - oldValues = { - ...oldValues, - ...userMeta, - } - oldValues.phone = oldValues.phone - ? emailEncryption.decrypt(oldValues.phone) - : oldValues.phone + } + oldValues = + isOrgUpdate || + isRoleUpdated || + modifiedKeys.length > 0 || + additionalCsvHeaders.length > 0 + ? { ...userFetch, ...oldValues } + : {} + oldValues = { + ...oldValues, + ...userMeta, } + oldValues.email = oldValues?.email + ? emailEncryption.decrypt(oldValues.email) + : oldValues?.email + oldValues.phone = oldValues?.phone + ? emailEncryption.decrypt(oldValues.phone) + : oldValues?.phone if (Object.keys(oldValues).length > 0 || Object.keys(newValues).length > 0) { const eventBody = eventBodyDTO({ entity: 'user', @@ -916,8 +921,6 @@ module.exports = class UserInviteHelper { username: userUpdate[0].dataValues?.username, status: userUpdate[0].dataValues?.status, deleted: userUpdate[0].dataValues?.deleted_at ? true : false, - tenant_code: user.tenant_code, - organization_code: user.organization_code, created_at: userUpdate[0].dataValues?.created_at || null, updated_at: userUpdate[0].dataValues?.updated_at || new Date(), oldValues, @@ -1136,8 +1139,9 @@ module.exports = class UserInviteHelper { created_by: user.id, name: parsedData?.name, username: parsedData?.username, - email: raw_email, + email: raw_email ? raw_email : null, phone: parsedData?.phone ? parsedData?.phone : null, + phone_code: parsedData?.phone_code ? parsedData?.phone_code : null, organizations, tenant_code: user?.tenant_code, ...metaData, From b8558a19a1252e7f70f68c830fc19075200018ca Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Thu, 16 Oct 2025 11:24:20 +0530 Subject: [PATCH 3/5] code rabbit comments --- src/helpers/userInvite.js | 73 ++++++++++++++------------------------- 1 file changed, 25 insertions(+), 48 deletions(-) diff --git a/src/helpers/userInvite.js b/src/helpers/userInvite.js index 162282356..58c04c032 100644 --- a/src/helpers/userInvite.js +++ b/src/helpers/userInvite.js @@ -20,11 +20,11 @@ const ProjectRootDir = path.join(__dirname, '../') const inviteeFileDir = ProjectRootDir + common.tempFolderForBulkUpload const entityTypeQueries = require('@database/queries/entityType') const UserCredentialQueries = require('@database/queries/userCredential') -const { Op } = require('sequelize') +const { Op, and } = require('sequelize') const emailEncryption = require('@utils/emailEncryption') const userOrganizationQueries = require('@database/queries/userOrganization') const userOrganizationRoleQueries = require('@database/queries/userOrganizationRole') -const { eventBodyDTO, keysFilter } = require('@dtos/userDTO') +const { eventBodyDTO, keysFilter, transformUser } = require('@dtos/userDTO') const { broadcastEvent } = require('@helpers/eventBroadcasterMain') const { generateUniqueUsername, generateUniqueCodeString } = require('@utils/usernameGenerator.js') const userRolesQueries = require('@database/queries/userOrganizationRole') @@ -822,24 +822,22 @@ module.exports = class UserInviteHelper { userUpdateData.meta || userUpdateData.password_update ) { - // const userCred = await UserCredentialQueries.findOne({ - // email: encryptedEmail, - // }) - const [count, userUpdate] = await userQueries.updateUser( { id: existingUser.id }, userUpdateData ) updatedUserIds.push(existingUser.id) - + // find the keys which are modified let modifiedKeys = Object.keys(userUpdate[0].dataValues).filter((key) => { const current = userUpdate[0].dataValues[key] const previous = userUpdate[0]._previousDataValues[key] return current !== previous && !_.isEqual(current, previous) }) + // remove critical and obvious datas from the keys to be sent in event modifiedKeys = keysFilter(modifiedKeys) - let oldValues = {}, + // format old values for event and remove transform it to match the standards + let oldValues = transformUser(userUpdate[0]?._previousDataValues) || {}, newValues = {}, userFetch = isOrgUpdate || @@ -851,19 +849,16 @@ module.exports = class UserInviteHelper { {}, user.tenant_code ) - : {} - + : {} // fetch the user with organization and roles if any of the critical fields are updated userFetch = userFetch?.[0] || {} + // if org or role is updated assign the old and new values if (isOrgUpdate || isRoleUpdated) { oldValues.organizations = existingUser.organizations - newValues.organizations = userFetch.organizations + newValues.organizations = userFetch?.organizations } - let userMeta = {} - + // if any keys are modified in user table or additional csv headers are present prepare the new values if (modifiedKeys.length > 0 || additionalCsvHeaders.length > 0) { - userMeta = { ...userFetch?.meta } - userFetch = await utils.processDbResponse(userFetch, prunedEntities) const comparisonKeys = [...modifiedKeys, ...additionalCsvHeaders] comparisonKeys.forEach((modifiedKey) => { if (modifiedKey == 'meta') { @@ -891,26 +886,25 @@ module.exports = class UserInviteHelper { user meta with entity and _id from external micro-service is passed with entity information and value of the _ids to prarse it to a standard format with data for emitting the event */ - userMeta = utils.parseMetaData(userMeta, prunedEntities, externalEntityNameIdMap) } - oldValues = - isOrgUpdate || - isRoleUpdated || - modifiedKeys.length > 0 || - additionalCsvHeaders.length > 0 - ? { ...userFetch, ...oldValues } - : {} + // parse meta data to fetch the entity name and value instead of _ids + const userOldMeta = oldValues?.meta + ? utils.parseMetaData(oldValues.meta, prunedEntities, externalEntityNameIdMap) + : {} + // delete the meta raw field + delete oldValues.meta + // merge the parsed meta data with old values oldValues = { ...oldValues, - ...userMeta, + ...userOldMeta, + } + // decrypt email and phone for event + if (oldValues?.email) { + oldValues.email = emailEncryption.decrypt(oldValues.email) + } + if (oldValues?.phone) { + oldValues.phone = emailEncryption.decrypt(oldValues.phone) } - - oldValues.email = oldValues?.email - ? emailEncryption.decrypt(oldValues.email) - : oldValues?.email - oldValues.phone = oldValues?.phone - ? emailEncryption.decrypt(oldValues.phone) - : oldValues?.phone if (Object.keys(oldValues).length > 0 || Object.keys(newValues).length > 0) { const eventBody = eventBodyDTO({ entity: 'user', @@ -931,23 +925,6 @@ module.exports = class UserInviteHelper { broadcastEvent('userEvents', { requestBody: eventBody, isInternal: true }) } - // Update UserCredential with organization_id and potentially password - // const credentialUpdateData = { organization_id: user.organization_id } - - // // Add password to update data if provided - // if (invitee.password) { - // // Assuming you have a password hashing utility - // // You might need to adjust this based on your password handling - // credentialUpdateData.password = invitee.password // Consider hashing - // } - - // await UserCredentialQueries.updateUser( - // { - // email: encryptedEmail, - // }, - // credentialUpdateData - // ) - const currentRoles = existingUser.roles.map((role) => role.title) let newRoles = [] if (userUpdateData?.roles) { From e60da9c51e8997c4c52281908759db9c54072cad Mon Sep 17 00:00:00 2001 From: adithya_dinesh <96181253+adithyadinesh0412@users.noreply.github.com> Date: Thu, 16 Oct 2025 16:00:26 +0530 Subject: [PATCH 4/5] Remove unused 'and' import from sequelize --- src/helpers/userInvite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/userInvite.js b/src/helpers/userInvite.js index 58c04c032..8718e0e3c 100644 --- a/src/helpers/userInvite.js +++ b/src/helpers/userInvite.js @@ -20,7 +20,7 @@ const ProjectRootDir = path.join(__dirname, '../') const inviteeFileDir = ProjectRootDir + common.tempFolderForBulkUpload const entityTypeQueries = require('@database/queries/entityType') const UserCredentialQueries = require('@database/queries/userCredential') -const { Op, and } = require('sequelize') +const { Op } = require('sequelize') const emailEncryption = require('@utils/emailEncryption') const userOrganizationQueries = require('@database/queries/userOrganization') const userOrganizationRoleQueries = require('@database/queries/userOrganizationRole') From 683f04fd259c43df7887f02c24c6bf24234a9bfb Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Thu, 16 Oct 2025 16:55:11 +0530 Subject: [PATCH 5/5] Org Migration error message fix --- src/helpers/userInvite.js | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/helpers/userInvite.js b/src/helpers/userInvite.js index 81e7526b2..4699ab577 100644 --- a/src/helpers/userInvite.js +++ b/src/helpers/userInvite.js @@ -39,7 +39,15 @@ let externalEntityNameIdMap = {} let emailAndPhoneMissing = false let updatedUserIds = [] let loginUrl = '' - +const outPutFileKeys = ['name', 'email', 'phone_code', 'phone', 'username', 'password', 'roles', 'statusOrUserId'] // final output file headers +const filterOutput = (input) => { + return outPutFileKeys.reduce((acc, key) => { + if (input.hasOwnProperty(key)) { + acc[key] = input[key] + } + return acc + }, {}) +} module.exports = class UserInviteHelper { static async uploadInvites(data) { return new Promise(async (resolve, reject) => { @@ -559,8 +567,9 @@ module.exports = class UserInviteHelper { if (invitee.phone && !invitee.phone_code) { invalidFields.push('phone_code') } - // check if the phone is duplicate + if (invitee.phone && invitee.phone_code) { + // check if the phone is duplicate if (duplicateChecker.includes(`${invitee.phone_code}${invitee.phone}`)) { duplicateValues.push('phone') } @@ -644,7 +653,7 @@ module.exports = class UserInviteHelper { invitee.roles = invitee.roles.length > 0 ? invitee.roles.join(',') : '' delete invitee.meta invitee.statusOrUserId = errorMessageArray.join('. ') - input.push(invitee) + input.push(filterOutput(invitee)) continue } @@ -673,7 +682,7 @@ module.exports = class UserInviteHelper { : 'User already exist or invited' invitee.roles = invitee.roles.length > 0 ? invitee.roles.join(',') : '' delete invitee.meta - input.push(invitee) + input.push(filterOutput(invitee)) continue } @@ -703,6 +712,7 @@ module.exports = class UserInviteHelper { ) if (currentOrgs.length <= 0) { invitee.statusOrUserId = `User not found in tenant : ${user.tenant_code} ` + input.push(filterOutput(invitee)) continue } await userOrganizationQueries.changeUserOrganization({ @@ -926,23 +936,6 @@ module.exports = class UserInviteHelper { broadcastEvent('userEvents', { requestBody: eventBody, isInternal: true }) } - // Update UserCredential with organization_id and potentially password - // const credentialUpdateData = { organization_id: user.organization_id } - - // // Add password to update data if provided - // if (invitee.password) { - // // Assuming you have a password hashing utility - // // You might need to adjust this based on your password handling - // credentialUpdateData.password = invitee.password // Consider hashing - // } - - // await UserCredentialQueries.updateUser( - // { - // email: encryptedEmail, - // }, - // credentialUpdateData - // ) - const currentRoles = existingUser.roles.map((role) => role.title) let newRoles = [] if (userUpdateData?.roles) { @@ -993,6 +986,8 @@ module.exports = class UserInviteHelper { } else { //user doesn't have access to update user data invitee.statusOrUserId = 'Unauthorised to bulk upload user from another organisation' + invitee.roles = invitee.roles.length > 0 ? invitee.roles.join(',') : '' + input.push(filterOutput(invitee)) continue } } @@ -1313,7 +1308,7 @@ module.exports = class UserInviteHelper { invitee.statusOrUserId = `${invitee.statusOrUserId} , Login URL : ${loginUrl}` } delete invitee.meta - input.push(invitee) + input.push(filterOutput(invitee)) } if (updatedUserIds.length > 0) { // flush all user active sessions after update