Skip to content

Conversation

@vaivk369
Copy link

@vaivk369 vaivk369 commented Dec 28, 2025

…rties of undefined (reading 'outputFilePath')

Summary by CodeRabbit

  • New Features

    • Added self-service account creation flow with optional immediate sign-in and token/session issuance.
    • Tenant/domain resolution added so account creation can infer tenant context from domain or request headers.
    • Tenant-facing endpoint to create accounts exposed.
  • Bug Fixes

    • Added safety checks to avoid runtime errors when metadata or linked entities are missing.
    • Improved resilience around token/session persistence and cleanup.
  • Chores

    • Enhanced logging and per-user enrichment when listing users.

✏️ Tip: You can customize this high-level summary in your review settings.

…rties of undefined (reading 'outputFilePath')
@coderabbitai
Copy link

coderabbitai bot commented Dec 28, 2025

Walkthrough

Added defensive null-checking in parseMetaData and introduced tenant-aware account creation and optional in-registration login with token/session handling; also added a new Tenant controller endpoint delegating to the account service.

Changes

Cohort / File(s) Summary
Utils — defensive check
src/generics/utils.js
Guarded access to findEntity.data_type (uses existence check/optional chaining) to avoid runtime errors when pruned entity is missing.
Tenant controller — new endpoint
src/controllers/v1/tenant.js
Added accountCreate(req) which requires @services/account and forwards creation requests to the account service with try/catch error handling.
Account service — tenant & token flow
src/services/account.js
Extended create signature to create(bodyData, deviceInfo, domain, onlyCreate = false, req = {}). Added tenant/domain resolution, role selection from req.body.roles, conditional session/token generation (access & refresh), Redis persistence, session updates, debug logging, and resilient fallbacks; also adjusted list/decrypt/enrichment logic.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant TenantSvc as Tenant Lookup (DB/Service)
  participant AccountSvc as Account Service
  participant Auth as Token Generator / JWT
  participant Redis as Redis

  Client->>AccountSvc: POST /account.create(bodyData, deviceInfo, domain, onlyCreate?, req)
  alt domain provided
    AccountSvc->>TenantSvc: resolve tenant by domain
    TenantSvc-->>AccountSvc: tenantDetail / not found
  else no domain
    AccountSvc->>TenantSvc: resolve tenant by tenant_code from req.headers
    TenantSvc-->>AccountSvc: tenantDetail / not found
  end
  AccountSvc->>AccountSvc: validate input, select roles (req.body.roles || defaults)
  AccountSvc->>AccountSvc: create user record
  alt onlyCreate == false
    AccountSvc->>Auth: generate access & refresh tokens (tokenDetail includes user orgs & tenant)
    Auth-->>AccountSvc: access_token, refresh_token
    AccountSvc->>Redis: persist session & refresh token
    Redis-->>AccountSvc: ack
    AccountSvc-->>Client: return user + access_token + refresh_token
  else onlyCreate == true
    AccountSvc-->>Client: return created user (no tokens)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

A rabbit hops where code is new,
Resolves tenants and tokens too,
Guards in place to stop the fall,
Logs a trace and saves it all,
Hooray — no crash, just springtime debug! 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is truncated and incomplete, making it vague and unclear about the actual fix being implemented. Provide a complete, descriptive title that clearly explains the fix, such as 'Fix TypeError when creating users in bulk by adding null checks for entity data'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/generics/utils.js (2)

1022-1059: Note: Discrepancy between PR title and code change.

The PR title mentions "reading 'outputFilePath'" but the actual code change addresses accessing the data_type property on a potentially undefined findEntity. While the fix correctly prevents undefined property access errors, please verify that this change addresses the specific error mentioned in the PR title, or update the PR description to accurately reflect the fix.


1037-1055: Address fallback behavior when entity type is missing.

When findEntity is undefined (no matching entity in prunedEntities), the code falls through to the else block (lines 1049–1055). This processes metadata without entity type information and returns incomplete results like {name: undefined, id: undefined, externalId: undefined} if the corresponding data isn't found in feederData. The returned data is merged without validation into event bodies and change tracking structures across multiple call sites (account.js, user.js, userInvite.js), which could cause downstream issues. Either add validation to reject incomplete metadata or document why partial results are acceptable.

🧹 Nitpick comments (1)
src/generics/utils.js (1)

1041-1041: Defensive null-check correctly prevents the runtime error.

The added check for findEntity existence before accessing its data_type property prevents the "Cannot read properties of undefined" error when no matching entity is found in the prunedEntities array.

Minor note: The optional chaining findEntity?.data_type is redundant after the explicit findEntity && check, though it's harmless. Consider simplifying to:

🔎 Suggested simplification
-if (findEntity && (findEntity?.data_type == 'ARRAY' || findEntity?.data_type == 'ARRAY[STRING]')) {
+if (findEntity && (findEntity.data_type == 'ARRAY' || findEntity.data_type == 'ARRAY[STRING]')) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2025dd and 2191628.

⛔ Files ignored due to path filters (1)
  • src/api-doc/bulkUser.md is excluded by !src/api-doc/**, !**/*.md
📒 Files selected for processing (1)
  • src/generics/utils.js
🧰 Additional context used
🧬 Code graph analysis (1)
src/generics/utils.js (1)
src/helpers/userInvite.js (1)
  • findEntity (579-579)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/account.js (1)

322-334: Type safety issue with req.body.roles.

If req.body.roles is truthy but not a string (e.g., already an array), calling .split(',') will throw a TypeError. Consider adding type validation.

Proposed fix
 			role = await roleQueries.findAll(
 				{
 					title: {
-						[Op.in]: req.body.roles ? req.body.roles.split(',') : process.env.DEFAULT_ROLE.split(','),
+						[Op.in]: req.body.roles
+							? (Array.isArray(req.body.roles) ? req.body.roles : req.body.roles.split(','))
+							: process.env.DEFAULT_ROLE.split(','),
 					},
 					tenant_code: tenantDetail.code,
 				},
🤖 Fix all issues with AI agents
In `@src/controllers/v1/tenant.js`:
- Around line 162-168: The JSDoc for the "Create account user" endpoint has an
incorrect `@name` value; change the `@name` annotation from "bulkUserCreate" to
"accountCreate" in the JSDoc block above the accountCreate handler so the docs
match the actual method/intent (look for the comment block containing "Create
account user" and update its `@name`).

In `@src/services/account.js`:
- Around line 1946-1969: The code reads user.user_organizations[0] without
checking existence which can throw if a user has no organizations; update the
loop in the section using user_organizations to first verify
user.user_organizations && user.user_organizations.length > 0, and if absent
either skip processing that user (continue) or fall back to
defaultOrganizationCode for userOrg and handle the missing id when calling
removeDefaultOrgEntityTypes (e.g., pass null/undefined or guard that call).
Ensure the branches adjust the values passed to findUserEntityTypesAndEntities
and removeDefaultOrgEntityTypes and still call utils.processDbResponse only when
safe.
- Around line 384-385: Remove the two debug console.log statements that print
validationData and userModel; either delete them entirely or replace them with
structured logging using the project's logger (e.g., logger.debug or
processLogger.debug) and ensure sensitive fields from validationData/userModel
are omitted or redacted before logging; update occurrences of
console.log('validationData', validationData) and console.log('userModel',
userModel) in src/services/account.js accordingly.
- Line 42: Remove the unused import "use" from i18next in this module: delete
the line that destructures use from the require call (the symbol "use" in the
const { use } = require('i18next') statement) so the file no longer imports an
unused binding; if the require call is otherwise unnecessary, replace or
simplify it accordingly (e.g., remove the entire require if nothing else from
i18next is used).
- Around line 70-84: tenantDomain can be undefined if neither domain nor
req.headers[common.TENANT_CODE_HEADER] are present, causing a TypeError when
accessing tenantDomain.tenant_code in the tenantQueries.findOne call; update the
logic in the block using tenantDomain and tenantId (the code around
tenantDomain, tenantId, TENANT_CODE_HEADER and the notFoundResponse call) to
explicitly handle the missing-case by returning a notFoundResponse (or similar
error) when both domain and the tenant header are absent, or ensure tenantDomain
is initialized (e.g., set tenantDomain = { tenant_code: tenantId }) before
calling tenantQueries.findOne so tenantQueries.findOne always gets a valid
tenant_code.
🧹 Nitpick comments (3)
src/services/account.js (3)

115-116: Remove empty else block.

The empty else block adds no value and should be removed for code cleanliness.

Proposed fix
 			if (!domainDetails) {
 				return responses.failureResponse({
 					message: 'INVALID_ORG_registration_code',
 					statusCode: httpStatusCode.bad_request,
 					responseCode: 'CLIENT_ERROR',
 				})
 			}
-		} else {
 		}

506-512: Remove commented-out code.

Commented-out code should be removed. If this logic is needed in the future, it can be retrieved from version control.

Proposed fix
-		/* 			let tenantDetails = await organizationQueries.findOne(
-			{ id: user.organization_id },
-			{ attributes: ['related_orgs'] }
-		)
-
-		const tenant_id =
-			tenantDetails && tenantDetails.parent_id !== null ? tenantDetails.parent_id : user.organization_id */

1730-1730: Good defensive error handling.

Swallowing Redis deletion errors with .catch((err) => {}) is appropriate here since this is a fire-and-forget cache invalidation that shouldn't fail the main operation. However, consider logging the error for observability.

-		utilsHelper.redisDel(redisUserKey).catch((err) => {})
+		utilsHelper.redisDel(redisUserKey).catch((err) => {
+			console.error('Failed to delete Redis cache:', err)
+		})

Comment on lines +162 to +168
/**
* Create account user
* @method POST
* @name bulkUserCreate
* @param {Object} req -request data.
* @returns {JSON} - success or error message
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix JSDoc @name annotation.

The @name should be accountCreate, not bulkUserCreate.

Proposed fix
 	/**
 	 * Create account user
 	 * `@method` POST
-	 * `@name` bulkUserCreate
+	 * `@name` accountCreate
 	 * `@param` {Object} req -request data.
 	 * `@returns` {JSON} - success or error message
 	 */
🤖 Prompt for AI Agents
In `@src/controllers/v1/tenant.js` around lines 162 - 168, The JSDoc for the
"Create account user" endpoint has an incorrect `@name` value; change the `@name`
annotation from "bulkUserCreate" to "accountCreate" in the JSDoc block above the
accountCreate handler so the docs match the actual method/intent (look for the
comment block containing "Create account user" and update its `@name`).

const notificationUtils = require('@utils/notification')
const userHelper = require('@helpers/userHelper')
const { broadcastEvent } = require('@helpers/eventBroadcasterMain')
const { use } = require('i18next')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused import.

The use function is imported from i18next but never used in this file.

Proposed fix
-const { use } = require('i18next')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { use } = require('i18next')
🤖 Prompt for AI Agents
In `@src/services/account.js` at line 42, Remove the unused import "use" from
i18next in this module: delete the line that destructures use from the require
call (the symbol "use" in the const { use } = require('i18next') statement) so
the file no longer imports an unused binding; if the require call is otherwise
unnecessary, replace or simplify it accordingly (e.g., remove the entire require
if nothing else from i18next is used).

Comment on lines +70 to 84
let tenantDomain

const tenantDomain = await tenantDomainQueries.findOne({ domain })

if (!tenantDomain) {
return notFoundResponse('TENANT_DOMAIN_NOT_FOUND_PING_ADMIN')
if (domain) {
tenantDomain = await tenantDomainQueries.findOne({ domain })

if (!tenantDomain) {
return notFoundResponse('TENANT_DOMAIN_NOT_FOUND_PING_ADMIN')
}
} else if (req.headers?.[common.TENANT_CODE_HEADER]) {
tenantId = req.headers?.[common.TENANT_CODE_HEADER]
tenantDomain = { tenant_code: tenantId }
}

const tenantDetail = await tenantQueries.findOne({
code: tenantDomain.tenant_code,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Potential TypeError when both domain and tenant header are missing.

If domain is falsy and req.headers?.[common.TENANT_CODE_HEADER] is also undefined, tenantDomain remains undefined. Accessing tenantDomain.tenant_code on line 84 will throw a TypeError.

Proposed fix
 		if (domain) {
 			tenantDomain = await tenantDomainQueries.findOne({ domain })
 
 			if (!tenantDomain) {
 				return notFoundResponse('TENANT_DOMAIN_NOT_FOUND_PING_ADMIN')
 			}
 		} else if (req.headers?.[common.TENANT_CODE_HEADER]) {
 			tenantId = req.headers?.[common.TENANT_CODE_HEADER]
 			tenantDomain = { tenant_code: tenantId }
+		} else {
+			return notFoundResponse('TENANT_DOMAIN_OR_CODE_REQUIRED')
 		}
🤖 Prompt for AI Agents
In `@src/services/account.js` around lines 70 - 84, tenantDomain can be undefined
if neither domain nor req.headers[common.TENANT_CODE_HEADER] are present,
causing a TypeError when accessing tenantDomain.tenant_code in the
tenantQueries.findOne call; update the logic in the block using tenantDomain and
tenantId (the code around tenantDomain, tenantId, TENANT_CODE_HEADER and the
notFoundResponse call) to explicitly handle the missing-case by returning a
notFoundResponse (or similar error) when both domain and the tenant header are
absent, or ensure tenantDomain is initialized (e.g., set tenantDomain = {
tenant_code: tenantId }) before calling tenantQueries.findOne so
tenantQueries.findOne always gets a valid tenant_code.

Comment on lines +384 to +385
console.log('validationData', validationData)
console.log('userModel', userModel)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove debug console.log statements.

These debug statements should be removed before merging to production or converted to structured logging with appropriate log levels.

Proposed fix
-		console.log('validationData', validationData)
-		console.log('userModel', userModel)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log('validationData', validationData)
console.log('userModel', userModel)
🤖 Prompt for AI Agents
In `@src/services/account.js` around lines 384 - 385, Remove the two debug
console.log statements that print validationData and userModel; either delete
them entirely or replace them with structured logging using the project's logger
(e.g., logger.debug or processLogger.debug) and ensure sensitive fields from
validationData/userModel are omitted or redacted before logging; update
occurrences of console.log('validationData', validationData) and
console.log('userModel', userModel) in src/services/account.js accordingly.

Comment on lines +1946 to +1969
const defaultOrganizationCode = process.env.DEFAULT_ORGANISATION_CODE

for (let i = 0; i < users.data.length; i++) {
let user = users.data[i]

// Convert Sequelize instance to plain object
if (user.toJSON) {
user = user.toJSON()
users.data[i] = user
}

let userOrg = user.user_organizations[0].organization_code
let validationData = await entityTypeQueries.findUserEntityTypesAndEntities({
status: 'ACTIVE',
organization_code: {
[Op.in]: [userOrg, defaultOrganizationCode],
},
tenant_code: params.query.tenant_code,
model_names: { [Op.contains]: [await userQueries.getModelName()] },
})
const prunedEntities = removeDefaultOrgEntityTypes(validationData, user.user_organizations[0].id)
const processedUser = await utils.processDbResponse(user, prunedEntities)
Object.assign(user, processedUser)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing bounds check on user_organizations array.

Accessing user.user_organizations[0] without checking if the array exists and has elements could cause a runtime error if a user has no organizations.

Proposed fix
 			for (let i = 0; i < users.data.length; i++) {
 				let user = users.data[i]
 
 				// Convert Sequelize instance to plain object
 				if (user.toJSON) {
 					user = user.toJSON()
 					users.data[i] = user
 				}
 
+				if (!user.user_organizations?.length) {
+					continue
+				}
+
 				let userOrg = user.user_organizations[0].organization_code
🤖 Prompt for AI Agents
In `@src/services/account.js` around lines 1946 - 1969, The code reads
user.user_organizations[0] without checking existence which can throw if a user
has no organizations; update the loop in the section using user_organizations to
first verify user.user_organizations && user.user_organizations.length > 0, and
if absent either skip processing that user (continue) or fall back to
defaultOrganizationCode for userOrg and handle the missing id when calling
removeDefaultOrgEntityTypes (e.g., pass null/undefined or guard that call).
Ensure the branches adjust the values passed to findUserEntityTypesAndEntities
and removeDefaultOrgEntityTypes and still call utils.processDbResponse only when
safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant