998 workflow restore (#12417)
Add a post hook to restore workflow sub-entities
This commit is contained in:
@ -22,9 +22,10 @@ export class WorkflowDeleteManyPostQueryHook
|
||||
_objectName: string,
|
||||
payload: WorkflowWorkspaceEntity[],
|
||||
): Promise<void> {
|
||||
this.workflowCommonWorkspaceService.cleanWorkflowsSubEntities(
|
||||
payload.map((workflow) => workflow.id),
|
||||
authContext.workspace.id,
|
||||
);
|
||||
this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
|
||||
workflowIds: payload.map((workflow) => workflow.id),
|
||||
workspaceId: authContext.workspace.id,
|
||||
operation: 'delete',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,9 +22,10 @@ export class WorkflowDeleteOnePostQueryHook
|
||||
_objectName: string,
|
||||
payload: WorkflowWorkspaceEntity[],
|
||||
): Promise<void> {
|
||||
this.workflowCommonWorkspaceService.cleanWorkflowsSubEntities(
|
||||
payload.map((workflow) => workflow.id),
|
||||
authContext.workspace.id,
|
||||
);
|
||||
this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
|
||||
workflowIds: payload.map((workflow) => workflow.id),
|
||||
workspaceId: authContext.workspace.id,
|
||||
operation: 'delete',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
import { WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
import { DestroyManyResolverArgs } 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 { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
|
||||
@WorkspaceQueryHook('workflow.destroyMany')
|
||||
export class WorkflowDestroyManyPreQueryHook
|
||||
implements WorkspacePreQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
_objectName: string,
|
||||
payload: DestroyManyResolverArgs<{ id: { in: string[] } }>,
|
||||
): Promise<DestroyManyResolverArgs<{ id: { in: string[] } }>> {
|
||||
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
|
||||
workflowIds: payload.filter.id.in,
|
||||
workspaceId: authContext.workspace.id,
|
||||
operation: 'destroy',
|
||||
});
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
import { WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
import { DestroyOneResolverArgs } 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 { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
|
||||
@WorkspaceQueryHook('workflow.destroyOne')
|
||||
export class WorkflowDestroyOnePreQueryHook
|
||||
implements WorkspacePreQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
_objectName: string,
|
||||
payload: DestroyOneResolverArgs,
|
||||
): Promise<DestroyOneResolverArgs> {
|
||||
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
|
||||
workflowIds: [payload.id],
|
||||
workspaceId: authContext.workspace.id,
|
||||
operation: 'destroy',
|
||||
});
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@ -29,6 +29,10 @@ import { WorkflowVersionUpdateManyPreQueryHook } from 'src/modules/workflow/comm
|
||||
import { WorkflowVersionUpdateOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-version-update-one.pre-query.hook';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service';
|
||||
import { WorkflowRestoreOnePostQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-restore-one.post-query.hook';
|
||||
import { WorkflowRestoreManyPostQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-restore-many.post-query.hook';
|
||||
import { WorkflowDestroyOnePreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-destroy-one.pre-query.hook';
|
||||
import { WorkflowDestroyManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-destroy-many.pre-query.hook';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -49,6 +53,8 @@ import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/
|
||||
WorkflowRunUpdateManyPreQueryHook,
|
||||
WorkflowRunDeleteOnePreQueryHook,
|
||||
WorkflowRunDeleteManyPreQueryHook,
|
||||
WorkflowRestoreOnePostQueryHook,
|
||||
WorkflowRestoreManyPostQueryHook,
|
||||
WorkflowVersionCreateOnePreQueryHook,
|
||||
WorkflowVersionCreateManyPreQueryHook,
|
||||
WorkflowVersionUpdateOnePreQueryHook,
|
||||
@ -61,6 +67,8 @@ import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/
|
||||
WorkflowCommonWorkspaceService,
|
||||
WorkflowDeleteManyPostQueryHook,
|
||||
WorkflowDeleteOnePostQueryHook,
|
||||
WorkflowDestroyOnePreQueryHook,
|
||||
WorkflowDestroyManyPreQueryHook,
|
||||
],
|
||||
})
|
||||
export class WorkflowQueryHookModule {}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
import { WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
|
||||
@WorkspaceQueryHook({
|
||||
key: 'workflow.restoreMany',
|
||||
type: WorkspaceQueryHookType.POST_HOOK,
|
||||
})
|
||||
export class WorkflowRestoreManyPostQueryHook
|
||||
implements WorkspacePostQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
_objectName: string,
|
||||
payload: WorkflowWorkspaceEntity[],
|
||||
): Promise<void> {
|
||||
this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
|
||||
workflowIds: payload.map((workflow) => workflow.id),
|
||||
workspaceId: authContext.workspace.id,
|
||||
operation: 'restore',
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
import { WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
|
||||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||
|
||||
@WorkspaceQueryHook({
|
||||
key: 'workflow.restoreOne',
|
||||
type: WorkspaceQueryHookType.POST_HOOK,
|
||||
})
|
||||
export class WorkflowRestoreOnePostQueryHook
|
||||
implements WorkspacePostQueryHookInstance
|
||||
{
|
||||
constructor(
|
||||
private readonly workflowCommonWorkspaceService: WorkflowCommonWorkspaceService,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
authContext: AuthContext,
|
||||
_objectName: string,
|
||||
payload: WorkflowWorkspaceEntity[],
|
||||
): Promise<void> {
|
||||
this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
|
||||
workflowIds: payload.map((workflow) => workflow.id),
|
||||
workspaceId: authContext.workspace.id,
|
||||
operation: 'restore',
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||
import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util';
|
||||
@ -19,6 +18,7 @@ import {
|
||||
WorkflowTriggerException,
|
||||
WorkflowTriggerExceptionCode,
|
||||
} from 'src/modules/workflow/workflow-trigger/exceptions/workflow-trigger.exception';
|
||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||
|
||||
export type ObjectMetadataInfo = {
|
||||
objectMetadataItemWithFieldsMaps: ObjectMetadataItemWithFieldMaps;
|
||||
@ -114,10 +114,15 @@ export class WorkflowCommonWorkspaceService {
|
||||
};
|
||||
}
|
||||
|
||||
async cleanWorkflowsSubEntities(
|
||||
workflowIds: string[],
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
async handleWorkflowSubEntities({
|
||||
workflowIds,
|
||||
workspaceId,
|
||||
operation,
|
||||
}: {
|
||||
workflowIds: string[];
|
||||
workspaceId: string;
|
||||
operation: 'restore' | 'delete' | 'destroy';
|
||||
}): Promise<void> {
|
||||
const workflowVersionRepository =
|
||||
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
|
||||
'workflowVersion',
|
||||
@ -133,46 +138,91 @@ export class WorkflowCommonWorkspaceService {
|
||||
'workflowAutomatedTrigger',
|
||||
);
|
||||
|
||||
workflowIds.forEach((workflowId) => {
|
||||
workflowAutomatedTriggerRepository.softDelete({
|
||||
workflowId,
|
||||
});
|
||||
for (const workflowId of workflowIds) {
|
||||
switch (operation) {
|
||||
case 'delete':
|
||||
await workflowAutomatedTriggerRepository.softDelete({
|
||||
workflowId,
|
||||
});
|
||||
|
||||
workflowRunRepository.softDelete({
|
||||
workflowId,
|
||||
});
|
||||
await workflowRunRepository.softDelete({
|
||||
workflowId,
|
||||
});
|
||||
|
||||
workflowVersionRepository.softDelete({
|
||||
workflowId,
|
||||
});
|
||||
await workflowVersionRepository.softDelete({
|
||||
workflowId,
|
||||
});
|
||||
|
||||
this.deleteServerlessFunctions(
|
||||
break;
|
||||
case 'restore':
|
||||
await workflowAutomatedTriggerRepository.restore({
|
||||
workflowId,
|
||||
});
|
||||
|
||||
await workflowRunRepository.restore({
|
||||
workflowId,
|
||||
});
|
||||
|
||||
await workflowVersionRepository.restore({
|
||||
workflowId,
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
await this.handleServerlessFunctionSubEntities({
|
||||
workflowVersionRepository,
|
||||
workflowId,
|
||||
workspaceId,
|
||||
);
|
||||
});
|
||||
operation,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteServerlessFunctions(
|
||||
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>,
|
||||
workflowId: string,
|
||||
workspaceId: string,
|
||||
) {
|
||||
async handleServerlessFunctionSubEntities({
|
||||
workflowVersionRepository,
|
||||
workflowId,
|
||||
workspaceId,
|
||||
operation,
|
||||
}: {
|
||||
workflowVersionRepository: WorkspaceRepository<WorkflowVersionWorkspaceEntity>;
|
||||
|
||||
workflowId: string;
|
||||
|
||||
workspaceId: string;
|
||||
operation: 'restore' | 'delete' | 'destroy';
|
||||
}) {
|
||||
const workflowVersions = await workflowVersionRepository.find({
|
||||
where: {
|
||||
workflowId,
|
||||
},
|
||||
withDeleted: true,
|
||||
});
|
||||
|
||||
workflowVersions.forEach((workflowVersion) => {
|
||||
workflowVersion.steps?.forEach(async (step) => {
|
||||
if (step.type === WorkflowActionType.CODE) {
|
||||
await this.serverlessFunctionService.deleteOneServerlessFunction({
|
||||
id: step.settings.input.serverlessFunctionId,
|
||||
workspaceId,
|
||||
isHardDeletion: false,
|
||||
});
|
||||
switch (operation) {
|
||||
case 'delete':
|
||||
await this.serverlessFunctionService.deleteOneServerlessFunction({
|
||||
id: step.settings.input.serverlessFunctionId,
|
||||
workspaceId,
|
||||
softDelete: true,
|
||||
});
|
||||
break;
|
||||
case 'restore':
|
||||
await this.serverlessFunctionService.restoreOneServerlessFunction(
|
||||
step.settings.input.serverlessFunctionId,
|
||||
);
|
||||
break;
|
||||
case 'destroy':
|
||||
await this.serverlessFunctionService.deleteOneServerlessFunction({
|
||||
id: step.settings.input.serverlessFunctionId,
|
||||
workspaceId,
|
||||
softDelete: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -375,6 +375,7 @@ export class WorkflowVersionStepWorkspaceService {
|
||||
await this.serverlessFunctionService.deleteOneServerlessFunction({
|
||||
id: step.settings.input.serverlessFunctionId,
|
||||
workspaceId,
|
||||
softDelete: false,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
WorkflowVersionBatchEvent,
|
||||
WorkflowVersionEventType,
|
||||
} from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job';
|
||||
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
|
||||
describe('WorkflowStatusesUpdate', () => {
|
||||
let job: WorkflowStatusesUpdateJob;
|
||||
@ -73,6 +74,14 @@ describe('WorkflowStatusesUpdate', () => {
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: getRepositoryToken(ServerlessFunctionEntity, 'metadata'),
|
||||
useValue: {
|
||||
findOneOrFail: jest.fn().mockResolvedValue({
|
||||
latestVersion: 'v2',
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ import {
|
||||
WorkflowAction,
|
||||
WorkflowActionType,
|
||||
} from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
|
||||
export enum WorkflowVersionEventType {
|
||||
CREATE = 'CREATE',
|
||||
@ -75,6 +76,8 @@ export class WorkflowStatusesUpdateJob {
|
||||
private readonly workspaceEventEmitter: WorkspaceEventEmitter,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
protected readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
@InjectRepository(ServerlessFunctionEntity, 'metadata')
|
||||
private readonly serverlessFunctionRepository: Repository<ServerlessFunctionEntity>,
|
||||
) {}
|
||||
|
||||
@Process(WorkflowStatusesUpdateJob.name)
|
||||
@ -212,9 +215,11 @@ export class WorkflowStatusesUpdateJob {
|
||||
}
|
||||
|
||||
const serverlessFunction =
|
||||
await this.serverlessFunctionService.findOneOrFail({
|
||||
id: step.settings.input.serverlessFunctionId,
|
||||
workspaceId,
|
||||
await this.serverlessFunctionRepository.findOneOrFail({
|
||||
where: {
|
||||
id: step.settings.input.serverlessFunctionId,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
const newStepSettings = { ...step.settings };
|
||||
|
||||
@ -6,12 +6,14 @@ import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless
|
||||
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
|
||||
import { WorkflowStatusesUpdateJob } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job';
|
||||
import { WorkflowVersionStatusListener } from 'src/modules/workflow/workflow-status/listeners/workflow-version-status.listener';
|
||||
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ServerlessFunctionModule,
|
||||
WorkspaceEventEmitterModule,
|
||||
TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
|
||||
TypeOrmModule.forFeature([ServerlessFunctionEntity], 'metadata'),
|
||||
],
|
||||
providers: [WorkflowStatusesUpdateJob, WorkflowVersionStatusListener],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user