fix(plugin-workflow): fix destroy node bug (#2553)

This commit is contained in:
Junyi 2023-08-28 21:33:53 +07:00 committed by GitHub
parent b23112fd2e
commit 1a82e92ae3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 19 deletions

View File

@ -0,0 +1,84 @@
import { MockServer } from '@nocobase/test';
import Database from '@nocobase/database';
import { getApp, sleep } from '..';
describe('workflow > actions > workflows', () => {
let app: MockServer;
let agent;
let db: Database;
let PostModel;
let PostRepo;
let WorkflowModel;
beforeEach(async () => {
app = await getApp();
agent = app.agent();
db = app.db;
WorkflowModel = db.getCollection('workflows').model;
PostModel = db.getCollection('posts').model;
PostRepo = db.getCollection('posts').repository;
});
afterEach(() => app.destroy());
describe('destroy', () => {
it('node in executed workflow could not be destroyed', async () => {
const workflow = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 1,
collection: 'posts',
},
});
const n1 = await workflow.createNode({
type: 'echo',
});
await PostRepo.create({});
await sleep(500);
const { status } = await agent.resource('flow_nodes').destroy({
filterByTk: n1.id,
});
expect(status).toBe(400);
});
it('cascading destroy all nodes in sub-branches', async () => {
const workflow = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 1,
collection: 'posts',
},
});
const n1 = await workflow.createNode({
type: 'echo',
});
const n2 = await workflow.createNode({
type: 'echo',
branchIndex: 0,
upstreamId: n1.id,
});
const n3 = await workflow.createNode({
type: 'echo',
branchIndex: 0,
upstreamId: n2.id,
});
await agent.resource('flow_nodes').destroy({
filterByTk: n1.id,
});
const nodes = await workflow.getNodes();
expect(nodes.length).toBe(0);
});
});
});

View File

@ -17,10 +17,10 @@ export default function ({ app }) {
...make('workflows', workflows), ...make('workflows', workflows),
...make('workflows.nodes', { ...make('workflows.nodes', {
create: nodes.create, create: nodes.create,
destroy: nodes.destroy,
}), }),
...make('flow_nodes', { ...make('flow_nodes', {
update: nodes.update, update: nodes.update,
destroy: nodes.destroy,
}), }),
...make('executions', executions), ...make('executions', executions),
}); });

View File

@ -1,5 +1,5 @@
import { Context, utils } from '@nocobase/actions'; import { Context, utils } from '@nocobase/actions';
import { MultipleRelationRepository, Op } from '@nocobase/database'; import { MultipleRelationRepository, Op, Repository } from '@nocobase/database';
import type { WorkflowModel } from '../types'; import type { WorkflowModel } from '../types';
export async function create(context: Context, next) { export async function create(context: Context, next) {
@ -109,22 +109,20 @@ function searchBranchDownstreams(nodes, from) {
export async function destroy(context: Context, next) { export async function destroy(context: Context, next) {
const { db } = context; const { db } = context;
const repository = utils.getRepositoryFromParams(context) as MultipleRelationRepository; const repository = utils.getRepositoryFromParams(context) as Repository;
const { filterByTk } = context.action.params; const { filterByTk } = context.action.params;
context.body = await db.sequelize.transaction(async (transaction) => { const fields = ['id', 'upstreamId', 'downstreamId', 'branchIndex'];
const workflow = (await repository.getSourceModel(transaction)) as WorkflowModel; const instance = await repository.findOne({
if (workflow.executed) { filterByTk,
context.throw(400, 'Nodes in executed workflow could not be deleted'); fields: [...fields, 'workflowId'],
} appends: ['upstream', 'downstream', 'workflow'],
});
if (instance.workflow.executed) {
context.throw(400, 'Nodes in executed workflow could not be deleted');
}
const fields = ['id', 'upstreamId', 'downstreamId', 'branchIndex']; await db.sequelize.transaction(async (transaction) => {
const instance = await repository.findOne({
filterByTk,
fields: [...fields, 'workflowId'],
appends: ['upstream', 'downstream'],
transaction,
});
const { upstream, downstream } = instance.get(); const { upstream, downstream } = instance.get();
if (upstream && upstream.downstreamId === instance.id) { if (upstream && upstream.downstreamId === instance.id) {
@ -159,7 +157,7 @@ export async function destroy(context: Context, next) {
nodesMap.set(item.id, item); nodesMap.set(item.id, item);
}); });
// overwrite // overwrite
nodesMap.set(instance.id, instance); // nodesMap.set(instance.id, instance);
// make linked list // make linked list
nodes.forEach((item) => { nodes.forEach((item) => {
if (item.upstreamId) { if (item.upstreamId) {
@ -170,16 +168,16 @@ export async function destroy(context: Context, next) {
} }
}); });
const branchNodes = searchBranchNodes(nodes, instance); const branchNodes = searchBranchNodes(nodes, nodesMap.get(instance.id));
await repository.destroy({ await repository.destroy({
filterByTk: [instance.id, ...branchNodes.map((item) => item.id)], filterByTk: [instance.id, ...branchNodes.map((item) => item.id)],
transaction, transaction,
}); });
return instance;
}); });
context.body = instance;
await next(); await next();
} }