Add workflow query hooks (#6876)

Workflow version :
- prevent status to be update manually
- prevent creation / deletion in another status than draft
- prevent creation if a draft already exists

Workflow:
- prevent statuses to set manually

WorkflowRun:
- prevent all manual operations
This commit is contained in:
Thomas Trompette
2024-09-03 17:07:22 +02:00
committed by GitHub
parent 612428eeb3
commit 50a65ef46b
29 changed files with 535 additions and 62 deletions

View File

@@ -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,
],

View File

@@ -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',
}

View File

@@ -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<CreateManyResolverArgs<WorkflowRunWorkspaceEntity>> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<CreateOneResolverArgs<WorkflowRunWorkspaceEntity>> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<DeleteManyResolverArgs<WorkflowRunWorkspaceEntity>> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<DeleteOneResolverArgs> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<UpdateManyResolverArgs<WorkflowRunWorkspaceEntity>> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<UpdateOneResolverArgs<WorkflowRunWorkspaceEntity>> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<WorkflowVersionWorkspaceEntity>,
) {
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<WorkflowVersionWorkspaceEntity>(
'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<WorkflowVersionWorkspaceEntity>,
) {
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);
}
}

View File

@@ -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<WorkflowVersionWorkspaceEntity, 'trigger'> & {
trigger: WorkflowTrigger;
},
) => {
if (workflowVersion.status !== WorkflowVersionStatus.DRAFT) {
throw new WorkflowQueryValidationException(
'Workflow version is not in draft status',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
};

View File

@@ -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<WorkflowVersionWorkspaceEntity>,
): Promise<CreateManyResolverArgs<WorkflowVersionWorkspaceEntity>> {
await Promise.all(
payload.data.map(async (workflowVersion) => {
await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne(
{
data: workflowVersion,
} satisfies CreateOneResolverArgs<WorkflowVersionWorkspaceEntity>,
);
}),
);
return payload;
}
}

View File

@@ -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<WorkflowVersionWorkspaceEntity>,
): Promise<CreateOneResolverArgs<WorkflowVersionWorkspaceEntity>> {
await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForCreateOne(
payload,
);
return payload;
}
}

View File

@@ -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<WorkflowVersionWorkspaceEntity>
> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<DeleteOneResolverArgs> {
await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForDeleteOne(
payload,
);
return payload;
}
}

View File

@@ -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<WorkflowVersionWorkspaceEntity>
> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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`)

View File

@@ -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',
}

View File

@@ -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<WorkflowVersionWorkspaceEntity>,
) {
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,
);
}
}
}

View File

@@ -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,
);
}
};

View File

@@ -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,
);
}
};

View File

@@ -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<WorkflowWorkspaceEntity>,
): Promise<CreateManyResolverArgs<WorkflowWorkspaceEntity>> {
payload.data.forEach((workflow) => {
assertWorkflowStatusesNotSetOrEmpty(workflow.statuses);
});
return payload;
}
}

View File

@@ -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<WorkflowWorkspaceEntity>,
): Promise<CreateOneResolverArgs<WorkflowWorkspaceEntity>> {
assertWorkflowStatusesNotSetOrEmpty(payload.data.statuses);
return payload;
}
}

View File

@@ -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<UpdateManyResolverArgs<WorkflowWorkspaceEntity>> {
throw new WorkflowQueryValidationException(
'Method not allowed.',
WorkflowQueryValidationExceptionCode.FORBIDDEN,
);
}
}

View File

@@ -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<WorkflowWorkspaceEntity>,
): Promise<UpdateOneResolverArgs<WorkflowWorkspaceEntity>> {
assertWorkflowStatusesNotSet(payload.data.statuses);
return payload;
}
}

View File

@@ -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],

View File

@@ -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';

View File

@@ -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,

View File

@@ -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';