From 7dfb9dd77fd8832dfee527f4ea84b504b62e40ca Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Tue, 4 Feb 2025 17:13:29 +0100 Subject: [PATCH] Fix send email error when empty connected account (#10005) - Fix send email error when empty connected account - Add a global util to valid uuid - Add an util to check if object is workflow related --- .../hooks/useFilteredObjectMetadataItems.ts | 9 ++------- .../object-metadata/hooks/useObjectMetadataItem.ts | 7 ++----- .../utils/isWorkflowRelatedObjectMetadata.ts | 9 +++++++++ .../utils/getSpreadSheetFieldValidationDefinitions.ts | 3 +-- .../components/WorkflowSingleRecordPicker.tsx | 3 +-- .../src/utils/__tests__/isValidUuid.test.ts | 11 ----------- .../utils/assert-is-valid-uuid.util.ts | 9 +++------ .../exceptions/send-email-action.exception.ts | 1 + .../mail-sender/send-email.workflow-action.ts | 9 ++++++++- .../src/utils/strings/__tests__/isValidUuid.test.ts | 11 +++++++++++ packages/twenty-shared/src/utils/strings/index.ts | 1 + .../src/utils/strings/isValidUuid.util.ts} | 0 12 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-metadata/utils/isWorkflowRelatedObjectMetadata.ts delete mode 100644 packages/twenty-front/src/utils/__tests__/isValidUuid.test.ts create mode 100644 packages/twenty-shared/src/utils/strings/__tests__/isValidUuid.test.ts rename packages/{twenty-front/src/utils/isValidUuid.ts => twenty-shared/src/utils/strings/isValidUuid.util.ts} (100%) diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts index eb947c622..966260562 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts @@ -1,8 +1,7 @@ import { useRecoilValue } from 'recoil'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata'; +import { isWorkflowRelatedObjectMetadata } from '@/object-metadata/utils/isWorkflowRelatedObjectMetadata'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; @@ -14,11 +13,7 @@ export const useFilteredObjectMetadataItems = () => { ); const isWorkflowToBeFiltered = (nameSingular: string) => { - return ( - !isWorkflowEnabled && - (nameSingular === CoreObjectNameSingular.Workflow || - isWorkflowSubObjectMetadata(nameSingular)) - ); + return !isWorkflowEnabled && isWorkflowRelatedObjectMetadata(nameSingular); }; const activeObjectMetadataItems = objectMetadataItems.filter( diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts index a3a5df952..979b6a366 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts @@ -5,8 +5,7 @@ import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objec import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { isDefined } from 'twenty-shared'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata'; +import { isWorkflowRelatedObjectMetadata } from '@/object-metadata/utils/isWorkflowRelatedObjectMetadata'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier'; @@ -26,9 +25,7 @@ export const useObjectMetadataItem = ({ ); const isWorkflowToBeFiltered = - !isWorkflowEnabled && - (objectNameSingular === CoreObjectNameSingular.Workflow || - isWorkflowSubObjectMetadata(objectNameSingular)); + !isWorkflowEnabled && isWorkflowRelatedObjectMetadata(objectNameSingular); const objectMetadataItems = useRecoilValue(objectMetadataItemsState); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/isWorkflowRelatedObjectMetadata.ts b/packages/twenty-front/src/modules/object-metadata/utils/isWorkflowRelatedObjectMetadata.ts new file mode 100644 index 000000000..77087fd64 --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/utils/isWorkflowRelatedObjectMetadata.ts @@ -0,0 +1,9 @@ +import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata'; +import { CoreObjectNameSingular } from '../types/CoreObjectNameSingular'; + +export const isWorkflowRelatedObjectMetadata = (objectNameSingular: string) => { + return ( + objectNameSingular === CoreObjectNameSingular.Workflow || + isWorkflowSubObjectMetadata(objectNameSingular) + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts b/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts index 3907ed8f7..89f20e960 100644 --- a/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts +++ b/packages/twenty-front/src/modules/object-record/spreadsheet-import/utils/getSpreadSheetFieldValidationDefinitions.ts @@ -1,7 +1,6 @@ import { FieldValidationDefinition } from '@/spreadsheet-import/types'; -import { isDefined } from 'twenty-shared'; +import { isDefined, isValidUuid } from 'twenty-shared'; import { FieldMetadataType } from '~/generated-metadata/graphql'; -import { isValidUuid } from '~/utils/isValidUuid'; import { absoluteUrlSchema } from '~/utils/validation-schemas/absoluteUrlSchema'; export const getSpreadSheetFieldValidationDefinitions = ( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker.tsx index e6da76708..fb37b76e9 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowSingleRecordPicker.tsx @@ -16,9 +16,8 @@ import { WorkflowVariablesDropdown } from '@/workflow/workflow-variables/compone import { css } from '@emotion/react'; import styled from '@emotion/styled'; import { useCallback } from 'react'; -import { isDefined } from 'twenty-shared'; +import { isDefined, isValidUuid } from 'twenty-shared'; import { IconChevronDown, IconForbid, LightIconButton } from 'twenty-ui'; -import { isValidUuid } from '~/utils/isValidUuid'; const StyledFormSelectContainer = styled(FormFieldInputInputContainer)` justify-content: space-between; diff --git a/packages/twenty-front/src/utils/__tests__/isValidUuid.test.ts b/packages/twenty-front/src/utils/__tests__/isValidUuid.test.ts deleted file mode 100644 index 768972b53..000000000 --- a/packages/twenty-front/src/utils/__tests__/isValidUuid.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { isValidUuid } from '~/utils/isValidUuid'; - -describe('isValidUuid', () => { - it('returns true if value is a valid UUID', () => { - expect(isValidUuid('bec09e27-4ecc-4a85-afc1-f2c0ace28bfa')).toBe(true); - }); - - it('returns false if value is not a valid UUID', () => { - expect(isValidUuid('123e4567-e89b-12d3-a456-42661417400')).toBe(false); - }); -}); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util.ts index 27c4b6c14..801f7ddb4 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util.ts @@ -1,15 +1,12 @@ +import { isValidUuid } from 'twenty-shared'; + import { WorkspaceQueryRunnerException, WorkspaceQueryRunnerExceptionCode, } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-runner.exception'; export const assertIsValidUuid = (value: string) => { - const isValid = - /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i.test( - value, - ); - - if (!isValid) { + if (!isValidUuid(value)) { throw new WorkspaceQueryRunnerException( `Value "${value}" is not a valid UUID`, WorkspaceQueryRunnerExceptionCode.INVALID_QUERY_INPUT, diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts index 346749425..229a70b88 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception.ts @@ -11,4 +11,5 @@ export enum SendEmailActionExceptionCode { PROVIDER_NOT_SUPPORTED = 'PROVIDER_NOT_SUPPORTED', CONNECTED_ACCOUNT_NOT_FOUND = 'CONNECTED_ACCOUNT_NOT_FOUND', INVALID_EMAIL = 'INVALID_EMAIL', + INVALID_CONNECTED_ACCOUNT_ID = 'INVALID_CONNECTED_ACCOUNT_ID', } diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action.ts index 49464640a..2ba4e9442 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action.ts @@ -2,8 +2,8 @@ import { Injectable, Logger } from '@nestjs/common'; import DOMPurify from 'dompurify'; import { JSDOM } from 'jsdom'; +import { isDefined, isValidUuid } from 'twenty-shared'; import { z } from 'zod'; -import { isDefined } from 'twenty-shared'; import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface'; @@ -36,6 +36,13 @@ export class SendEmailWorkflowAction implements WorkflowAction { ) {} private async getEmailClient(connectedAccountId: string) { + if (!isValidUuid(connectedAccountId)) { + throw new SendEmailActionException( + `Connected Account ID is not a valid UUID`, + SendEmailActionExceptionCode.INVALID_CONNECTED_ACCOUNT_ID, + ); + } + const { workspaceId } = this.scopedWorkspaceContextFactory.create(); if (!workspaceId) { diff --git a/packages/twenty-shared/src/utils/strings/__tests__/isValidUuid.test.ts b/packages/twenty-shared/src/utils/strings/__tests__/isValidUuid.test.ts new file mode 100644 index 000000000..1eb494e9b --- /dev/null +++ b/packages/twenty-shared/src/utils/strings/__tests__/isValidUuid.test.ts @@ -0,0 +1,11 @@ +import { isValidUuid } from '../isValidUuid.util'; + +describe('isValidUuid', () => { + it('should return true for a valid UUID', () => { + expect(isValidUuid('123e4567-e89b-12d3-a456-426614174000')).toBe(true); + }); + + it('should return false for an invalid UUID', () => { + expect(isValidUuid('123e4567-e89b-12d3-a456-426614174000')).toBe(false); + }); +}); diff --git a/packages/twenty-shared/src/utils/strings/index.ts b/packages/twenty-shared/src/utils/strings/index.ts index 707424b37..ef55c7241 100644 --- a/packages/twenty-shared/src/utils/strings/index.ts +++ b/packages/twenty-shared/src/utils/strings/index.ts @@ -1 +1,2 @@ export * from './capitalize.util'; +export * from './isValidUuid.util'; diff --git a/packages/twenty-front/src/utils/isValidUuid.ts b/packages/twenty-shared/src/utils/strings/isValidUuid.util.ts similarity index 100% rename from packages/twenty-front/src/utils/isValidUuid.ts rename to packages/twenty-shared/src/utils/strings/isValidUuid.util.ts