diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts index e280459ec369..7601f628cbc1 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-hook.module.ts @@ -1,12 +1,34 @@ import { Module } from '@nestjs/common'; -import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook'; -import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service'; -import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; +import { WorkflowRunCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-many.pre-query.hook'; +import { WorkflowRunCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-one.pre-query.hook'; +import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service'; +import { WorkflowVersionCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-many.pre-query.hook'; +import { WorkflowVersionCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-one.pre-query.hook'; +import { WorkflowVersionDeleteManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-many.pre-query.hook'; +import { WorkflowVersionDeleteOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-one.pre-query.hook'; +import { WorkflowVersionUpdateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-many.pre-query.hook'; +import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query.hook'; +import { WorkflowCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow/workflow-create-many.pre-query.hook'; +import { WorkflowCreateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow/workflow-create-one.pre-query.hook'; +import { WorkflowUpdateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow/workflow-update-many.pre-query.hook'; +import { WorkflowUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow/workflow-update-one.pre-query.hook'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/services/workflow-common.workspace-service'; @Module({ providers: [ + WorkflowCreateOnePreQueryHook, + WorkflowCreateManyPreQueryHook, + WorkflowUpdateOnePreQueryHook, + WorkflowUpdateManyPreQueryHook, + WorkflowRunCreateOnePreQueryHook, + WorkflowRunCreateManyPreQueryHook, + WorkflowVersionCreateOnePreQueryHook, + WorkflowVersionCreateManyPreQueryHook, WorkflowVersionUpdateOnePreQueryHook, + WorkflowVersionUpdateManyPreQueryHook, + WorkflowVersionDeleteOnePreQueryHook, + WorkflowVersionDeleteManyPreQueryHook, WorkflowVersionValidationWorkspaceService, WorkflowCommonWorkspaceService, ], diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-validation.exception.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-validation.exception.ts new file mode 100644 index 000000000000..7ff0fb35daa8 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-query-validation.exception.ts @@ -0,0 +1,11 @@ +import { CustomException } from 'src/utils/custom-exception'; + +export class WorkflowQueryValidationException extends CustomException { + constructor(message: string, code: WorkflowQueryValidationExceptionCode) { + super(message, code); + } +} + +export enum WorkflowQueryValidationExceptionCode { + FORBIDDEN = 'FORBIDDEN', +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-many.pre-query.hook.ts new file mode 100644 index 000000000000..d12dd3166309 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-many.pre-query.hook.ts @@ -0,0 +1,21 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; + +@WorkspaceQueryHook(`workflowRun.createMany`) +export class WorkflowRunCreateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise> { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-one.pre-query.hook.ts new file mode 100644 index 000000000000..f8620b11b03c --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-create-one.pre-query.hook.ts @@ -0,0 +1,21 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; + +@WorkspaceQueryHook(`workflowRun.createOne`) +export class WorkflowRunCreateOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise> { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-delete-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-delete-many.pre-query.hook.ts new file mode 100644 index 000000000000..da9dbbaac96d --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-delete-many.pre-query.hook.ts @@ -0,0 +1,21 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { DeleteManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; + +@WorkspaceQueryHook(`workflowRun.deleteMany`) +export class WorkflowRunDeleteManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise> { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-delete-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-delete-one.pre-query.hook.ts new file mode 100644 index 000000000000..dcfb87744787 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-delete-one.pre-query.hook.ts @@ -0,0 +1,20 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; + +@WorkspaceQueryHook(`workflowRun.deleteOne`) +export class WorkflowRunDeleteOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-update-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-update-many.pre-query.hook.ts new file mode 100644 index 000000000000..5b1342ed8672 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-update-many.pre-query.hook.ts @@ -0,0 +1,21 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; + +@WorkspaceQueryHook(`workflowRun.updateMany`) +export class WorkflowRunUpdateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise> { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-update-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-update-one.pre-query.hook.ts new file mode 100644 index 000000000000..f33f1783c642 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-run/workflow-run-update-one.pre-query.hook.ts @@ -0,0 +1,21 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; + +@WorkspaceQueryHook(`workflowRun.updateOne`) +export class WorkflowRunUpdateOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise> { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service.ts new file mode 100644 index 000000000000..3d7c77b19887 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service.ts @@ -0,0 +1,88 @@ +import { Injectable } from '@nestjs/common'; + +import { + CreateOneResolverArgs, + DeleteOneResolverArgs, + UpdateOneResolverArgs, +} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { assertWorkflowVersionIsDraft } from 'src/modules/workflow/common/query-hooks/workflow-version/utils/assert-workflow-version-is-draft.util'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/services/workflow-common.workspace-service'; +import { + WorkflowVersionStatus, + WorkflowVersionWorkspaceEntity, +} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; + +@Injectable() +export class WorkflowVersionValidationWorkspaceService { + constructor( + private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService, + private readonly twentyORMManager: TwentyORMManager, + ) {} + + async validateWorkflowVersionForCreateOne( + payload: CreateOneResolverArgs, + ) { + if ( + payload.data.status && + payload.data.status !== WorkflowVersionStatus.DRAFT + ) { + throw new WorkflowQueryValidationException( + 'Cannot create workflow version with status other than draft', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } + + const workflowVersionRepository = + await this.twentyORMManager.getRepository( + 'workflowVersion', + ); + + const workflowAlreadyHasDraftVersion = + await workflowVersionRepository.exists({ + where: { + workflowId: payload.data.workflowId, + status: WorkflowVersionStatus.DRAFT, + }, + }); + + if (workflowAlreadyHasDraftVersion) { + throw new WorkflowQueryValidationException( + 'Cannot create multiple draft versions for the same workflow', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } + } + + async validateWorkflowVersionForUpdateOne( + payload: UpdateOneResolverArgs, + ) { + const workflowVersion = + await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail( + payload.id, + ); + + assertWorkflowVersionIsDraft(workflowVersion); + + if (payload.data.status !== workflowVersion.status) { + throw new WorkflowQueryValidationException( + 'Cannot update workflow version status manually', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } + } + + async validateWorkflowVersionForDeleteOne(payload: DeleteOneResolverArgs) { + const workflowVersion = + await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail( + payload.id, + ); + + assertWorkflowVersionIsDraft(workflowVersion); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/utils/assert-workflow-version-is-draft.util.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/utils/assert-workflow-version-is-draft.util.ts new file mode 100644 index 000000000000..2604f63fb2ca --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/utils/assert-workflow-version-is-draft.util.ts @@ -0,0 +1,22 @@ +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { + WorkflowVersionStatus, + WorkflowVersionWorkspaceEntity, +} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; +import { WorkflowTrigger } from 'src/modules/workflow/common/types/workflow-trigger.type'; + +export const assertWorkflowVersionIsDraft = ( + workflowVersion: Omit & { + trigger: WorkflowTrigger; + }, +) => { + if (workflowVersion.status !== WorkflowVersionStatus.DRAFT) { + throw new WorkflowQueryValidationException( + 'Workflow version is not in draft status', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +}; diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-many.pre-query.hook.ts new file mode 100644 index 000000000000..8d27ac88bf9c --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-many.pre-query.hook.ts @@ -0,0 +1,37 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { + CreateManyResolverArgs, + CreateOneResolverArgs, +} from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service'; +import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; + +@WorkspaceQueryHook(`workflowVersion.createMany`) +export class WorkflowVersionCreateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor( + private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, + ) {} + + async execute( + _authContext: AuthContext, + _objectName: string, + payload: CreateManyResolverArgs, + ): Promise> { + await Promise.all( + payload.data.map(async (workflowVersion) => { + await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne( + { + data: workflowVersion, + } satisfies CreateOneResolverArgs, + ); + }), + ); + + return payload; + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-one.pre-query.hook.ts new file mode 100644 index 000000000000..98d5c9d05d1b --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-create-one.pre-query.hook.ts @@ -0,0 +1,28 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service'; +import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; + +@WorkspaceQueryHook(`workflowVersion.createOne`) +export class WorkflowVersionCreateOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor( + private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, + ) {} + + async execute( + _authContext: AuthContext, + _objectName: string, + payload: CreateOneResolverArgs, + ): Promise> { + await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne( + payload, + ); + + return payload; + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-many.pre-query.hook.ts new file mode 100644 index 000000000000..f47e11472397 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-many.pre-query.hook.ts @@ -0,0 +1,23 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { DeleteManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; + +@WorkspaceQueryHook(`workflowVersion.deleteMany`) +export class WorkflowVersionDeleteManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise< + DeleteManyResolverArgs + > { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-one.pre-query.hook.ts new file mode 100644 index 000000000000..f4cd1a48f1fe --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-delete-one.pre-query.hook.ts @@ -0,0 +1,27 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service'; + +@WorkspaceQueryHook(`workflowVersion.deleteOne`) +export class WorkflowVersionDeleteOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + constructor( + private readonly workflowVersionValidationWorkspaceService: WorkflowVersionValidationWorkspaceService, + ) {} + + async execute( + _authContext: AuthContext, + _objectName: string, + payload: DeleteOneResolverArgs, + ): Promise { + await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForDeleteOne( + payload, + ); + + return payload; + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-many.pre-query.hook.ts new file mode 100644 index 000000000000..beba6071f4ae --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-many.pre-query.hook.ts @@ -0,0 +1,23 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; + +@WorkspaceQueryHook(`workflowVersion.updateMany`) +export class WorkflowVersionUpdateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise< + UpdateManyResolverArgs + > { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query.hook.ts similarity index 92% rename from packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook.ts rename to packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query.hook.ts index ffdde1a922f2..a8421cc113b0 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query-hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-update-one.pre-query.hook.ts @@ -3,7 +3,7 @@ import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; -import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service'; +import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/query-hooks/workflow-version/services/workflow-version-validation.workspace-service'; import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; @WorkspaceQueryHook(`workflowVersion.updateOne`) diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception.ts deleted file mode 100644 index b37d23ee9d93..000000000000 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { CustomException } from 'src/utils/custom-exception'; - -export class WorkflowVersionValidationException extends CustomException { - constructor(message: string, code: WorkflowVersionValidationExceptionCode) { - super(message, code); - } -} - -export enum WorkflowVersionValidationExceptionCode { - FORBIDDEN = 'FORBIDDEN', -} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service.ts deleted file mode 100644 index 88aa0d76f145..000000000000 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.workspace-service.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; - -import { - WorkflowVersionValidationException, - WorkflowVersionValidationExceptionCode, -} from 'src/modules/workflow/common/query-hooks/workflow-version/workflow-version-validation.exception'; -import { - WorkflowVersionStatus, - WorkflowVersionWorkspaceEntity, -} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; -import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; - -@Injectable() -export class WorkflowVersionValidationWorkspaceService { - constructor( - private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService, - ) {} - - async validateWorkflowVersionForUpdateOne( - payload: UpdateOneResolverArgs, - ) { - const workflowVersion = - await this.workflowCommonWorkspaceService.getWorkflowVersionOrFail( - payload.id, - ); - - if (workflowVersion.status !== WorkflowVersionStatus.DRAFT) { - throw new WorkflowVersionValidationException( - 'Only draft workflow versions can be updated', - WorkflowVersionValidationExceptionCode.FORBIDDEN, - ); - } - - if (payload.data.status !== workflowVersion.status) { - throw new WorkflowVersionValidationException( - 'Cannot update workflow version status manually', - WorkflowVersionValidationExceptionCode.FORBIDDEN, - ); - } - } -} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set-or-empty.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set-or-empty.ts new file mode 100644 index 000000000000..1bead159279e --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set-or-empty.ts @@ -0,0 +1,16 @@ +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowStatus } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; + +export const assertWorkflowStatusesNotSetOrEmpty = ( + statuses?: WorkflowStatus[] | null, +) => { + if (statuses && statuses.length > 0) { + throw new WorkflowQueryValidationException( + 'Statuses cannot be set manually.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +}; diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set.ts new file mode 100644 index 000000000000..0949551c262b --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set.ts @@ -0,0 +1,16 @@ +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowStatus } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; + +export const assertWorkflowStatusesNotSet = ( + statuses?: WorkflowStatus[] | null, +) => { + if (statuses) { + throw new WorkflowQueryValidationException( + 'Statuses cannot be set manually.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +}; diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-create-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-create-many.pre-query.hook.ts new file mode 100644 index 000000000000..cb6f6d943c5e --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-create-many.pre-query.hook.ts @@ -0,0 +1,24 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { assertWorkflowStatusesNotSetOrEmpty } from 'src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set-or-empty'; +import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; + +@WorkspaceQueryHook(`workflow.createMany`) +export class WorkflowCreateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute( + _authContext: AuthContext, + _objectName: string, + payload: CreateManyResolverArgs, + ): Promise> { + payload.data.forEach((workflow) => { + assertWorkflowStatusesNotSetOrEmpty(workflow.statuses); + }); + + return payload; + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-create-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-create-one.pre-query.hook.ts new file mode 100644 index 000000000000..92371364920b --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-create-one.pre-query.hook.ts @@ -0,0 +1,22 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { assertWorkflowStatusesNotSetOrEmpty } from 'src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set-or-empty'; +import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; + +@WorkspaceQueryHook(`workflow.createOne`) +export class WorkflowCreateOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute( + _authContext: AuthContext, + _objectName: string, + payload: CreateOneResolverArgs, + ): Promise> { + assertWorkflowStatusesNotSetOrEmpty(payload.data.statuses); + + return payload; + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-update-many.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-update-many.pre-query.hook.ts new file mode 100644 index 000000000000..e18e1d017ed8 --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-update-many.pre-query.hook.ts @@ -0,0 +1,21 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { + WorkflowQueryValidationException, + WorkflowQueryValidationExceptionCode, +} from 'src/modules/workflow/common/query-hooks/workflow-query-validation.exception'; +import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; + +@WorkspaceQueryHook(`workflow.updateMany`) +export class WorkflowUpdateManyPreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute(): Promise> { + throw new WorkflowQueryValidationException( + 'Method not allowed.', + WorkflowQueryValidationExceptionCode.FORBIDDEN, + ); + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-update-one.pre-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-update-one.pre-query.hook.ts new file mode 100644 index 000000000000..096c8044ef3e --- /dev/null +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow/workflow-update-one.pre-query.hook.ts @@ -0,0 +1,22 @@ +import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; +import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; + +import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; +import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { assertWorkflowStatusesNotSet } from 'src/modules/workflow/common/query-hooks/workflow/utils/assert-workflow-statuses-not-set'; +import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity'; + +@WorkspaceQueryHook(`workflow.updateOne`) +export class WorkflowUpdateOnePreQueryHook + implements WorkspaceQueryHookInstance +{ + async execute( + _authContext: AuthContext, + _objectName: string, + payload: UpdateOneResolverArgs, + ): Promise> { + assertWorkflowStatusesNotSet(payload.data.statuses); + + return payload; + } +} diff --git a/packages/twenty-server/src/modules/workflow/common/workflow-common.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/services/workflow-common.workspace-service.ts similarity index 100% rename from packages/twenty-server/src/modules/workflow/common/workflow-common.workspace-service.ts rename to packages/twenty-server/src/modules/workflow/common/services/workflow-common.workspace-service.ts diff --git a/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts b/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts index dfa97d4f7b80..bc9b9a9f086c 100644 --- a/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts +++ b/packages/twenty-server/src/modules/workflow/common/workflow-common.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { WorkflowQueryHookModule } from 'src/modules/workflow/common/query-hooks/workflow-query-hook.module'; -import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/services/workflow-common.workspace-service'; @Module({ imports: [WorkflowQueryHookModule], diff --git a/packages/twenty-server/src/modules/workflow/workflow-runner/jobs/run-workflow.job.ts b/packages/twenty-server/src/modules/workflow/workflow-runner/jobs/run-workflow.job.ts index 7c544974fd87..1630b14c15a7 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-runner/jobs/run-workflow.job.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-runner/jobs/run-workflow.job.ts @@ -3,8 +3,8 @@ import { Scope } from '@nestjs/common'; import { Process } from 'src/engine/integrations/message-queue/decorators/process.decorator'; import { Processor } from 'src/engine/integrations/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/services/workflow-common.workspace-service'; import { WorkflowRunStatus } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; -import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; import { WorkflowExecutorWorkspaceService } from 'src/modules/workflow/workflow-executor/workflow-executor.workspace-service'; import { WorkflowRunWorkspaceService } from 'src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service'; diff --git a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts index ba71af333d48..126984f01251 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service.ts @@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common'; import { ActorMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/services/workflow-common.workspace-service'; import { WorkflowRunStatus, WorkflowRunWorkspaceEntity, } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity'; -import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; import { WorkflowRunException, WorkflowRunExceptionCode, diff --git a/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.workspace-service.ts index 8142bc2545bf..4e02b8b888fa 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-trigger/workflow-trigger.workspace-service.ts @@ -8,6 +8,7 @@ import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/s import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; +import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/services/workflow-common.workspace-service'; import { WorkflowVersionStatus, WorkflowVersionWorkspaceEntity, @@ -17,7 +18,6 @@ import { WorkflowTrigger, WorkflowTriggerType, } from 'src/modules/workflow/common/types/workflow-trigger.type'; -import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workflow-common.workspace-service'; import { WorkflowRunnerWorkspaceService } from 'src/modules/workflow/workflow-runner/workflow-runner.workspace-service'; import { WorkflowVersionStatusUpdate } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job'; import { DatabaseEventTriggerService } from 'src/modules/workflow/workflow-trigger/database-event-trigger/database-event-trigger.service';