Repository: ever-co/ever-gauzy
Pull request #8960: Release
Author: login: rahul-rocket
Created: 2025-05-15T10:50:07Z | Merged: 2025-05-15T10:52:14Z

# PR

- [x] Have you followed the [contributing guidelines](https://github.com/ever-co/ever-gauzy/blob/master/.github/CONTRIBUTING.md)?
- [x] Have you explained what your changes do, and why they add value?

**Please note: we will close your PR without comment if you do not check the boxes above and provide ALL requested information.**

---



Diff:
diff --git a/packages/core/src/lib/core/dto/base-query.dto.ts b/packages/core/src/lib/core/dto/base-query.dto.ts
index 80b0ea1b534..1a4f4c610db 100644
--- a/packages/core/src/lib/core/dto/base-query.dto.ts
+++ b/packages/core/src/lib/core/dto/base-query.dto.ts
@@ -100,29 +100,37 @@ export function escapeQueryWithParameters(nativeParameters: PlainObject): Tenant
 }
 
 /**
- * Recursively converts raw parameters, parsing booleans and handling arrays and objects.
+ * Parses the given value and converts it to a boolean using JSON.parse.
  *
- * @param parameters - Raw input parameters
- * @returns Converted parameters with booleans properly parsed
+ * @param value - The value to be parsed.
+ * @returns {boolean} - The boolean representation of the parsed value.
  */
-export function convertNativeParameters(parameters: PlainObject): any {
-	if (parameters === null || parameters === undefined) {
-		return parameters;
-	}
+export const parseBool = (value: any): boolean => Boolean(JSON.parse(value));
 
-	if (Array.isArray(parameters)) {
-		// Process each array item recursively
-		return parameters.map((item) => convertNativeParameters(item));
-	}
+/**
+ * Converts native parameters based on the database connection type.
+ *
+ * @param parameters - The parameters to be converted.
+ * @returns {any} - The converted parameters based on the database connection type.
+ */
+export const convertNativeParameters = (parameters: PlainObject): any => {
+	try {
+		if (Array.isArray(parameters)) {
+			// Process each array item recursively
+			return parameters.map((item) => convertNativeParameters(item));
+		}
 
-	if (typeof parameters === 'object') {
-		// Recursively convert nested objects
-		return Object.keys(parameters).reduce((acc, key) => {
-			acc[key] = convertNativeParameters(parameters[key]);
-			return acc;
-		}, {} as Record<string, any>);
-	}
+		if (typeof parameters === 'object' && parameters !== null) {
+			// Recursively convert nested objects
+			return Object.keys(parameters).reduce((acc, key) => {
+				acc[key] = convertNativeParameters(parameters[key]);
+				return acc;
+			}, {});
+		}
 
-	// Primitive value: try to parse boolean
-	return parseToBoolean(parameters);
-}
+		// Convert boolean values to their numeric representation
+		return parseBool(parameters);
+	} catch (error) {
+		return parameters;
+	}
+};
diff --git a/packages/core/src/lib/shared/validators/constraints/organization-belongs-to-user.constraint.ts b/packages/core/src/lib/shared/validators/constraints/organization-belongs-to-user.constraint.ts
index 8893374e177..8ecaa9233a5 100644
--- a/packages/core/src/lib/shared/validators/constraints/organization-belongs-to-user.constraint.ts
+++ b/packages/core/src/lib/shared/validators/constraints/organization-belongs-to-user.constraint.ts
@@ -1,6 +1,6 @@
 import { Injectable } from '@nestjs/common';
 import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';
-import { IOrganization } from '@gauzy/contracts';
+import { ID, IOrganization } from '@gauzy/contracts';
 import { isEmpty } from '@gauzy/utils';
 import { RequestContext } from '../../../core/context';
 import { MultiORM, MultiORMEnum, getORMType } from '../../../core/utils';
@@ -27,59 +27,64 @@ export class OrganizationBelongsToUserConstraint implements ValidatorConstraintI
 	 * @param value - The organization ID or organization object.
 	 * @returns {Promise<boolean>} - True if the user belongs to the organization, otherwise false.
 	 */
-	async validate(value: IOrganization['id'] | IOrganization): Promise<boolean> {
+	async validate(value: ID | IOrganization): Promise<boolean> {
 		if (isEmpty(value)) {
 			return true;
 		}
 
-		// 'value' can be either a string (organization ID) or an organization object.
-		const organizationId: string = typeof value === 'string' ? value : value.id;
+		const organizationId = typeof value === 'string' ? value : value.id;
 
 		// Use the consolidated ORM logic function
-		return await this.checkOrganizationExistence(organizationId);
+		return this.checkOrganizationExistence(organizationId);
 	}
 
 	/**
 	 * Checks if the given organization exists for the current user in the database.
 	 *
-	 * @param organizationId The ID of the organization.
+	 * @param organizationId - The ID of the organization.
 	 * @returns {Promise<boolean>} - True if found, false otherwise.
 	 */
 	async checkOrganizationExistence(organizationId: string): Promise<boolean> {
 		const tenantId = RequestContext.currentTenantId();
 		const userId = RequestContext.currentUserId();
 
+		if (!tenantId || !userId) {
+			return false;
+		}
+
 		try {
 			switch (ormType) {
-				case MultiORMEnum.MikroORM:
-					return !!(await this.mikroOrmUserOrganizationRepository.findOneOrFail({
+				case MultiORMEnum.MikroORM: {
+					await this.mikroOrmUserOrganizationRepository.findOneOrFail({
 						tenantId,
 						userId,
 						organizationId
-					}));
-				case MultiORMEnum.TypeORM:
-					return !!(await this.typeOrmUserOrganizationRepository.findOneByOrFail({
+					});
+					return true;
+				}
+				case MultiORMEnum.TypeORM: {
+					await this.typeOrmUserOrganizationRepository.findOneByOrFail({
 						tenantId,
 						userId,
 						organizationId
-					}));
+					});
+					return true;
+				}
 				default:
-					throw new Error(`Not implemented for ${ormType}`);
+					throw new Error(`ORM type "${ormType}" not implemented.`);
 			}
-		} catch (error) {
+		} catch {
 			return false;
 		}
 	}
 
 	/**
-	 * Gets the default error message when the validation fails.
-	 * @param validationArguments - Validation arguments containing the value.
+	 * Gets the default error message when validation fails.
+	 *
 	 * @returns {string} - Default error message.
 	 */
-	defaultMessage(validationArguments?: ValidationArguments): string {
-		const { value } = validationArguments;
-		return `The user with ID ${RequestContext.currentUserId()} is not associated with the specified organization (${JSON.stringify(
-			value
-		)}).`;
+	defaultMessage(): string {
+		const userId = RequestContext.currentUserId();
+		return `The user with ID ${userId} is not associated with the specified organization.`;
 	}
 }
diff --git a/packages/plugins/posthog/src/lib/posthog-event.interceptor.ts b/packages/plugins/posthog/src/lib/posthog-event.interceptor.ts
index a050b9cfba4..9181d35eb08 100644
--- a/packages/plugins/posthog/src/lib/posthog-event.interceptor.ts
+++ b/packages/plugins/posthog/src/lib/posthog-event.interceptor.ts
@@ -2,6 +2,7 @@ import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor, Opt
 import { ContextType, HttpArgumentsHost, RpcArgumentsHost, WsArgumentsHost } from '@nestjs/common/interfaces';
 import { Observable } from 'rxjs';
 import { tap } from 'rxjs/operators';
+import * as crypto from 'crypto';
 import { PosthogEventInterceptorOptions } from './posthog.interfaces';
 import { PosthogService } from './posthog.service';
 import { SanitizerUtil } from './utils';
@@ -289,7 +290,7 @@ export class PosthogEventInterceptor implements NestInterceptor {
 	 */
 	private extractUserId(request: any): string {
 		// Generate a random ID if no user identifier is found
-		const anonymousId = `anon-${Math.random().toString(36).substring(2, 15)}`;
+		const anonymousId = `anon-${crypto.randomUUID()}`;
 
 		// Check common user ID locations
 		return (


Reviews:
user: login: greptile-apps[bot]
body: 
## PR Summary

This PR enhances security and validation across multiple components in the Ever Gauzy platform, focusing on organization constraints, event tracking, and query handling.

- Improved organization validation in `packages/core/src/lib/shared/validators/constraints/organization-belongs-to-user.constraint.ts` with stronger type checking and null safety
- Enhanced security in `packages/plugins/posthog/src/lib/posthog-event.interceptor.ts` by using `crypto.randomUUID()` for anonymous user IDs
- Added robust error handling and boolean parsing in `packages/core/src/lib/core/dto/base-query.dto.ts` for query parameter processing
- Implemented block scoping for switch cases in organization constraint validation
- Removed redundant parameter stringification in error messages

<sub>3 file(s) reviewed, 3 comment(s)</sub>
<sub>[Edit PR Review Bot Settings](https://app.greptile.com/review/github) | [Greptile](https://greptile.com?utm_source=greptile_expert&utm_medium=github&utm_campaign=code_reviews&utm_content=ever-gauzy_8960)</sub>
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T10:50:54Z

Review comments:
diff_hunk: @@ -27,59 +27,64 @@ export class OrganizationBelongsToUserConstraint implements ValidatorConstraintI
 	 * @param value - The organization ID or organization object.
 	 * @returns {Promise<boolean>} - True if the user belongs to the organization, otherwise false.
 	 */
-	async validate(value: IOrganization['id'] | IOrganization): Promise<boolean> {
+	async validate(value: ID | IOrganization): Promise<boolean> {
 		if (isEmpty(value)) {
 			return true;
 		}
 
-		// 'value' can be either a string (organization ID) or an organization object.
-		const organizationId: string = typeof value === 'string' ? value : value.id;
+		const organizationId = typeof value === 'string' ? value : value.id;
 
 		// Use the consolidated ORM logic function
-		return await this.checkOrganizationExistence(organizationId);
+		return this.checkOrganizationExistence(organizationId);
 	}
 
 	/**
 	 * Checks if the given organization exists for the current user in the database.
 	 *
-	 * @param organizationId The ID of the organization.
+	 * @param organizationId - The ID of the organization.
 	 * @returns {Promise<boolean>} - True if found, false otherwise.
 	 */
 	async checkOrganizationExistence(organizationId: string): Promise<boolean> {
 		const tenantId = RequestContext.currentTenantId();
 		const userId = RequestContext.currentUserId();
 
+		if (!tenantId || !userId) {
+			return false;
+		}
+
 		try {
 			switch (ormType) {
-				case MultiORMEnum.MikroORM:
-					return !!(await this.mikroOrmUserOrganizationRepository.findOneOrFail({
+				case MultiORMEnum.MikroORM: {
+					await this.mikroOrmUserOrganizationRepository.findOneOrFail({
 						tenantId,
 						userId,
 						organizationId
-					}));
-				case MultiORMEnum.TypeORM:
-					return !!(await this.typeOrmUserOrganizationRepository.findOneByOrFail({
+					});
+					return true;
+				}
+				case MultiORMEnum.TypeORM: {
+					await this.typeOrmUserOrganizationRepository.findOneByOrFail({
 						tenantId,
 						userId,
 						organizationId
-					}));
+					});
+					return true;
+				}
 				default:
-					throw new Error(`Not implemented for ${ormType}`);
+					throw new Error(`ORM type "${ormType}" not implemented.`);
 			}
-		} catch (error) {
+		} catch {
 			return false;
 		}
path: packages/core/src/lib/shared/validators/constraints/organization-belongs-to-user.constraint.ts
user: login: greptile-apps[bot]
body: style: Consider logging the caught error for debugging purposes
created_at: 2025-05-15T10:50:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -100,29 +100,37 @@ export function escapeQueryWithParameters(nativeParameters: PlainObject): Tenant
 }
 
 /**
- * Recursively converts raw parameters, parsing booleans and handling arrays and objects.
+ * Parses the given value and converts it to a boolean using JSON.parse.
  *
- * @param parameters - Raw input parameters
- * @returns Converted parameters with booleans properly parsed
+ * @param value - The value to be parsed.
+ * @returns {boolean} - The boolean representation of the parsed value.
  */
-export function convertNativeParameters(parameters: PlainObject): any {
-	if (parameters === null || parameters === undefined) {
-		return parameters;
-	}
+export const parseBool = (value: any): boolean => Boolean(JSON.parse(value));
 
-	if (Array.isArray(parameters)) {
-		// Process each array item recursively
-		return parameters.map((item) => convertNativeParameters(item));
-	}
+/**
+ * Converts native parameters based on the database connection type.
+ *
+ * @param parameters - The parameters to be converted.
+ * @returns {any} - The converted parameters based on the database connection type.
+ */
+export const convertNativeParameters = (parameters: PlainObject): any => {
+	try {
+		if (Array.isArray(parameters)) {
+			// Process each array item recursively
+			return parameters.map((item) => convertNativeParameters(item));
+		}
 
-	if (typeof parameters === 'object') {
-		// Recursively convert nested objects
-		return Object.keys(parameters).reduce((acc, key) => {
-			acc[key] = convertNativeParameters(parameters[key]);
-			return acc;
-		}, {} as Record<string, any>);
-	}
+		if (typeof parameters === 'object' && parameters !== null) {
+			// Recursively convert nested objects
+			return Object.keys(parameters).reduce((acc, key) => {
+				acc[key] = convertNativeParameters(parameters[key]);
+				return acc;
+			}, {});
+		}
 
-	// Primitive value: try to parse boolean
-	return parseToBoolean(parameters);
-}
+		// Convert boolean values to their numeric representation
+		return parseBool(parameters);
path: packages/core/src/lib/core/dto/base-query.dto.ts
user: login: greptile-apps[bot]
body: logic: Using `parseBool` here will throw for non-JSON-parseable values. The previous `parseToBoolean` utility was more forgiving. This could break existing queries.

```suggestion
		// Convert boolean values to their numeric representation
		return parseToBoolean(parameters);
```
created_at: 2025-05-15T10:50:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -100,29 +100,37 @@ export function escapeQueryWithParameters(nativeParameters: PlainObject): Tenant
 }
 
 /**
- * Recursively converts raw parameters, parsing booleans and handling arrays and objects.
+ * Parses the given value and converts it to a boolean using JSON.parse.
  *
- * @param parameters - Raw input parameters
- * @returns Converted parameters with booleans properly parsed
+ * @param value - The value to be parsed.
+ * @returns {boolean} - The boolean representation of the parsed value.
  */
-export function convertNativeParameters(parameters: PlainObject): any {
-	if (parameters === null || parameters === undefined) {
-		return parameters;
-	}
+export const parseBool = (value: any): boolean => Boolean(JSON.parse(value));
path: packages/core/src/lib/core/dto/base-query.dto.ts
user: login: greptile-apps[bot]
body: style: JSON.parse will throw for invalid JSON strings. Consider using `parseToBoolean` from `@gauzy/utils` instead, which is already imported and handles edge cases better.

```suggestion
export const parseBool = (value: any): boolean => parseToBoolean(value);
```
created_at: 2025-05-15T10:50:38Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-15T10:50:15Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are disabled on base/target branches other than the default branch.
> 
> 
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ever-co/ever-gauzy&utm_content=8960):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: nx-cloud[bot]
created_at: 2025-05-15T11:16:10Z
body: 
View your [CI Pipeline Execution ↗](https://cloud.nx.app/cipes/6825ccf8cc4d642b1c690e39?utm_source=pull-request&utm_medium=comment) for commit 8466f566a2c96a635c157456cb3f188be0441b64.

| Command | Status | Duration | Result |
|---------|--------|----------:|--------|
| `nx build desktop --base-href ./` | ✅ Succeeded | 1m 51s | [View ↗](https://cloud.nx.app/runs/N1E1qLhkGl?utm_source=pull-request&utm_medium=comment) |
| `nx build desktop-api --output-path=dist/apps/de...` | ✅ Succeeded | 30s | [View ↗](https://cloud.nx.app/runs/Kl2Hjdn2FN?utm_source=pull-request&utm_medium=comment) |
| `nx run api:desktop-api` | ✅ Succeeded | 1m 16s | [View ↗](https://cloud.nx.app/runs/3EwkkknkUz?utm_source=pull-request&utm_medium=comment) |
| `nx run gauzy:desktop-ui --base-href ./` | ✅ Succeeded | 3m 34s | [View ↗](https://cloud.nx.app/runs/QKCtt9ILsM?utm_source=pull-request&utm_medium=comment) |
| `nx build gauzy -c=production --prod --verbose` | ✅ Succeeded | 3m 13s | [View ↗](https://cloud.nx.app/runs/4jVODma6e6?utm_source=pull-request&utm_medium=comment) |
| `nx build api -c=production --prod` | ✅ Succeeded | 1m 9s | [View ↗](https://cloud.nx.app/runs/IAMf5AXBiv?utm_source=pull-request&utm_medium=comment) |
| `nx build desktop-ui-lib --configuration=production` | ✅ Succeeded | 31s | [View ↗](https://cloud.nx.app/runs/4lvR6g4cbC?utm_source=pull-request&utm_medium=comment) |
| `nx build desktop-ui-lib --configuration=develop...` | ✅ Succeeded | 33s | [View ↗](https://cloud.nx.app/runs/9WEMsSA2rz?utm_source=pull-request&utm_medium=comment) |
| `Additional runs (62)` | ✅ Succeeded | ... | [View ↗](https://cloud.nx.app/cipes/6825ccf8cc4d642b1c690e39?utm_source=pull-request&utm_medium=comment) |

---

☁️ [Nx Cloud](https://cloud.nx.app?utm_source=pull-request&utm_medium=comment) last updated this comment at `2025-05-15 11:30:58` UTC

<!-- NX_CLOUD_APP_COMMENT_END -->
author_association: NONE