Filter valid fields in record steps (#17145)
Fixes https://github.com/twentyhq/twenty/issues/16775 When a field is deleted from the model, the workflow action step still stores the deleted field name in `step.settings.input.objectRecord`. We need to filter out the fields that are not valid anymore. This logic existed before but had been removed with the migration to tool services.
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
export const filterValidFieldsInRecord = (
|
||||
record: Record<string, unknown>,
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
): Record<string, unknown> => {
|
||||
const { fieldIdByName, fieldIdByJoinColumnName } =
|
||||
buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
const filteredRecord: Record<string, unknown> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(record)) {
|
||||
const fieldMetadataId = fieldIdByName[key] || fieldIdByJoinColumnName[key];
|
||||
|
||||
if (isDefined(fieldMetadataId)) {
|
||||
filteredRecord[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return filteredRecord;
|
||||
};
|
||||
+8
-1
@@ -14,6 +14,7 @@ import { WorkflowExecutionContextService } from 'src/modules/workflow/workflow-e
|
||||
import { type WorkflowActionInput } from 'src/modules/workflow/workflow-executor/types/workflow-action-input';
|
||||
import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executor/types/workflow-action-output.type';
|
||||
import { buildWorkflowActorMetadata } from 'src/modules/workflow/workflow-executor/utils/build-workflow-actor-metadata.util';
|
||||
import { filterValidFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/filter-valid-fields-in-record.util';
|
||||
import { findStepOrThrow } from 'src/modules/workflow/workflow-executor/utils/find-step-or-throw.util';
|
||||
import { resolveRichTextFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/resolve-rich-text-fields-in-record.util';
|
||||
import { type WorkflowCreateRecordActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
||||
@@ -61,6 +62,12 @@ export class CreateRecordWorkflowAction implements WorkflowAction {
|
||||
context,
|
||||
) as WorkflowCreateRecordActionInput;
|
||||
|
||||
const filteredObjectRecord = filterValidFieldsInRecord(
|
||||
workflowActionInput.objectRecord,
|
||||
objectMetadataInfo.flatObjectMetadata,
|
||||
objectMetadataInfo.flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
const executionContext =
|
||||
await this.workflowExecutionContextService.getExecutionContext(runInfo);
|
||||
|
||||
@@ -68,7 +75,7 @@ export class CreateRecordWorkflowAction implements WorkflowAction {
|
||||
|
||||
const toolOutput = await this.createRecordService.execute({
|
||||
objectName: workflowActionInput.objectName,
|
||||
objectRecord: workflowActionInput.objectRecord,
|
||||
objectRecord: filteredObjectRecord,
|
||||
authContext: executionContext.authContext,
|
||||
createdBy,
|
||||
rolePermissionConfig: executionContext.rolePermissionConfig,
|
||||
|
||||
+20
-2
@@ -18,6 +18,7 @@ import { WorkflowExecutionContextService } from 'src/modules/workflow/workflow-e
|
||||
import { type WorkflowActionInput } from 'src/modules/workflow/workflow-executor/types/workflow-action-input';
|
||||
import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executor/types/workflow-action-output.type';
|
||||
import { buildWorkflowActorMetadata } from 'src/modules/workflow/workflow-executor/utils/build-workflow-actor-metadata.util';
|
||||
import { filterValidFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/filter-valid-fields-in-record.util';
|
||||
import { findStepOrThrow } from 'src/modules/workflow/workflow-executor/utils/find-step-or-throw.util';
|
||||
import { resolveRichTextFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/resolve-rich-text-fields-in-record.util';
|
||||
import { isWorkflowUpdateRecordAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/guards/is-workflow-update-record-action.guard';
|
||||
@@ -84,6 +85,23 @@ export class UpdateRecordWorkflowAction implements WorkflowAction {
|
||||
);
|
||||
}
|
||||
|
||||
const filteredObjectRecord = filterValidFieldsInRecord(
|
||||
workflowActionInput.objectRecord,
|
||||
objectMetadataInfo.flatObjectMetadata,
|
||||
objectMetadataInfo.flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
const filteredFieldsToUpdate = workflowActionInput.fieldsToUpdate?.filter(
|
||||
(fieldName) => fieldName in filteredObjectRecord,
|
||||
);
|
||||
|
||||
if (filteredFieldsToUpdate?.length === 0) {
|
||||
throw new RecordCrudException(
|
||||
'Failed to update: No fields to update',
|
||||
RecordCrudExceptionCode.INVALID_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
const executionContext =
|
||||
await this.workflowExecutionContextService.getExecutionContext(runInfo);
|
||||
|
||||
@@ -92,8 +110,8 @@ export class UpdateRecordWorkflowAction implements WorkflowAction {
|
||||
const toolOutput = await this.updateRecordService.execute({
|
||||
objectName: workflowActionInput.objectName,
|
||||
objectRecordId: workflowActionInput.objectRecordId,
|
||||
objectRecord: workflowActionInput.objectRecord,
|
||||
fieldsToUpdate: workflowActionInput.fieldsToUpdate,
|
||||
objectRecord: filteredObjectRecord,
|
||||
fieldsToUpdate: filteredFieldsToUpdate,
|
||||
authContext: executionContext.authContext,
|
||||
updatedBy,
|
||||
rolePermissionConfig: executionContext.rolePermissionConfig,
|
||||
|
||||
+31
-2
@@ -9,6 +9,7 @@ import {
|
||||
RecordCrudExceptionCode,
|
||||
} from 'src/engine/core-modules/record-crud/exceptions/record-crud.exception';
|
||||
import { UpsertRecordService } from 'src/engine/core-modules/record-crud/services/upsert-record.service';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
import {
|
||||
WorkflowStepExecutorException,
|
||||
WorkflowStepExecutorExceptionCode,
|
||||
@@ -16,7 +17,9 @@ import {
|
||||
import { WorkflowExecutionContextService } from 'src/modules/workflow/workflow-executor/services/workflow-execution-context.service';
|
||||
import { type WorkflowActionInput } from 'src/modules/workflow/workflow-executor/types/workflow-action-input';
|
||||
import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executor/types/workflow-action-output.type';
|
||||
import { filterValidFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/filter-valid-fields-in-record.util';
|
||||
import { findStepOrThrow } from 'src/modules/workflow/workflow-executor/utils/find-step-or-throw.util';
|
||||
import { resolveRichTextFieldsInRecord } from 'src/modules/workflow/workflow-executor/utils/resolve-rich-text-fields-in-record.util';
|
||||
import { isWorkflowUpsertRecordAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/guards/is-workflow-upsert-record-action.guard';
|
||||
import { type WorkflowUpsertRecordActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
||||
|
||||
@@ -25,6 +28,7 @@ export class UpsertRecordWorkflowAction implements WorkflowAction {
|
||||
constructor(
|
||||
private readonly upsertRecordService: UpsertRecordService,
|
||||
private readonly workflowExecutionContextService: WorkflowExecutionContextService,
|
||||
private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService,
|
||||
) {}
|
||||
|
||||
async execute({
|
||||
@@ -45,8 +49,27 @@ export class UpsertRecordWorkflowAction implements WorkflowAction {
|
||||
);
|
||||
}
|
||||
|
||||
const { workspaceId } = runInfo;
|
||||
|
||||
const rawInput = step.settings.input as WorkflowUpsertRecordActionInput;
|
||||
|
||||
const objectMetadataInfo =
|
||||
await this.workflowCommonWorkspaceService.getObjectMetadataInfo(
|
||||
rawInput.objectName,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const inputWithResolvedRichText = {
|
||||
...rawInput,
|
||||
objectRecord: resolveRichTextFieldsInRecord(
|
||||
rawInput.objectRecord,
|
||||
objectMetadataInfo,
|
||||
context,
|
||||
),
|
||||
};
|
||||
|
||||
const workflowActionInput = resolveInput(
|
||||
step.settings.input,
|
||||
inputWithResolvedRichText,
|
||||
context,
|
||||
) as WorkflowUpsertRecordActionInput;
|
||||
|
||||
@@ -57,12 +80,18 @@ export class UpsertRecordWorkflowAction implements WorkflowAction {
|
||||
);
|
||||
}
|
||||
|
||||
const filteredObjectRecord = filterValidFieldsInRecord(
|
||||
workflowActionInput.objectRecord,
|
||||
objectMetadataInfo.flatObjectMetadata,
|
||||
objectMetadataInfo.flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
const executionContext =
|
||||
await this.workflowExecutionContextService.getExecutionContext(runInfo);
|
||||
|
||||
const toolOutput = await this.upsertRecordService.execute({
|
||||
objectName: workflowActionInput.objectName,
|
||||
objectRecord: workflowActionInput.objectRecord,
|
||||
objectRecord: filteredObjectRecord,
|
||||
authContext: executionContext.authContext,
|
||||
rolePermissionConfig: executionContext.rolePermissionConfig,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user