fix(plugin-workflow): fix workflow update action (#964)
This commit is contained in:
parent
ea4a9c2d6e
commit
42db519fa1
@ -6,7 +6,6 @@ import { getApp } from '.';
|
|||||||
|
|
||||||
describe('workflow > Plugin', () => {
|
describe('workflow > Plugin', () => {
|
||||||
let app: MockServer;
|
let app: MockServer;
|
||||||
let agent;
|
|
||||||
let db: Database;
|
let db: Database;
|
||||||
let PostModel;
|
let PostModel;
|
||||||
let PostRepo;
|
let PostRepo;
|
||||||
@ -14,7 +13,6 @@ describe('workflow > Plugin', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
app = await getApp();
|
app = await getApp();
|
||||||
agent = app.agent();
|
|
||||||
db = app.db;
|
db = app.db;
|
||||||
WorkflowModel = db.getCollection('workflows').model;
|
WorkflowModel = db.getCollection('workflows').model;
|
||||||
PostModel = db.getCollection('posts').model;
|
PostModel = db.getCollection('posts').model;
|
||||||
@ -155,173 +153,4 @@ describe('workflow > Plugin', () => {
|
|||||||
expect(c2).toBe(1);
|
expect(c2).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('revision', () => {
|
|
||||||
it('create revision', async () => {
|
|
||||||
const w1 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'collection',
|
|
||||||
config: {
|
|
||||||
mode: 1,
|
|
||||||
collection: 'posts'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const { body, status } = await agent.resource(`workflows`).revision({
|
|
||||||
filterByTk: w1.id
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(status).toBe(200);
|
|
||||||
const { data: w2 } = body;
|
|
||||||
expect(w2.config).toMatchObject(w1.config);
|
|
||||||
expect(w2.key).toBe(w1.key);
|
|
||||||
expect(w2.current).toBeFalsy();
|
|
||||||
expect(w2.enabled).toBe(false);
|
|
||||||
|
|
||||||
const p1 = await PostRepo.create({ values: { title: 't1' } });
|
|
||||||
|
|
||||||
await WorkflowModel.update({
|
|
||||||
enabled: true
|
|
||||||
}, {
|
|
||||||
where: {
|
|
||||||
id: w2.id
|
|
||||||
},
|
|
||||||
individualHooks: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const [w1next, w2next] = await WorkflowModel.findAll({
|
|
||||||
order: [['id', 'ASC']]
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(w1next.enabled).toBe(false);
|
|
||||||
expect(w1next.current).toBe(null);
|
|
||||||
expect(w2next.enabled).toBe(true);
|
|
||||||
expect(w2next.current).toBe(true);
|
|
||||||
|
|
||||||
const p2 = await PostRepo.create({ values: { title: 't2' } });
|
|
||||||
|
|
||||||
const [e1] = await w1next.getExecutions();
|
|
||||||
const [e2] = await w2next.getExecutions();
|
|
||||||
expect(e1.key).toBe(e2.key);
|
|
||||||
expect(e1.workflowId).toBe(w1.id);
|
|
||||||
expect(e2.workflowId).toBe(w2.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('revision with nodes', async () => {
|
|
||||||
const w1 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'collection',
|
|
||||||
config: {
|
|
||||||
mode: 1,
|
|
||||||
collection: 'posts'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const n1 = await w1.createNode({
|
|
||||||
type: 'echo'
|
|
||||||
});
|
|
||||||
const n2 = await w1.createNode({
|
|
||||||
type: 'calculation',
|
|
||||||
config: {
|
|
||||||
calculation: {
|
|
||||||
calculator: 'add',
|
|
||||||
operands: [
|
|
||||||
{
|
|
||||||
type: '$jobsMapByNodeId',
|
|
||||||
options: {
|
|
||||||
nodeId: n1.id,
|
|
||||||
path: 'data.read'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: `{{$jobsMapByNodeId.${n1.id}.data.read}}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
upstreamId: n1.id
|
|
||||||
});
|
|
||||||
await n1.setDownstream(n2);
|
|
||||||
|
|
||||||
const { body } = await agent.resource(`workflows`).revision({
|
|
||||||
filterByTk: w1.id
|
|
||||||
});
|
|
||||||
const w2 = await WorkflowModel.findByPk(body.data.id, {
|
|
||||||
include: [
|
|
||||||
'nodes'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const n1_2 = w2.nodes.find(n => !n.upstreamId);
|
|
||||||
const n2_2 = w2.nodes.find(n => !n.downstreamId);
|
|
||||||
|
|
||||||
expect(n1_2.type).toBe('echo');
|
|
||||||
expect(n2_2.type).toBe('calculation');
|
|
||||||
expect(n2_2.config).toMatchObject({
|
|
||||||
calculation: {
|
|
||||||
calculator: 'add',
|
|
||||||
operands: [
|
|
||||||
{
|
|
||||||
type: '$jobsMapByNodeId',
|
|
||||||
options: {
|
|
||||||
nodeId: n1_2.id,
|
|
||||||
path: 'data.read'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: `{{$jobsMapByNodeId.${n1_2.id}.data.read}}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await w2.update({ enabled: true });
|
|
||||||
|
|
||||||
await PostRepo.create({
|
|
||||||
values: { title: 't1', read: 1 }
|
|
||||||
});
|
|
||||||
|
|
||||||
const [execution] = await w2.getExecutions();
|
|
||||||
const [echo, calculation] = await execution.getJobs({ order: [['id', 'ASC']] });
|
|
||||||
expect(calculation.result).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('revision with using of deleted nodes', async () => {
|
|
||||||
const w1 = await WorkflowModel.create({
|
|
||||||
enabled: true,
|
|
||||||
type: 'collection',
|
|
||||||
config: {
|
|
||||||
mode: 1,
|
|
||||||
collection: 'posts'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const n2 = await w1.createNode({
|
|
||||||
type: 'calculation',
|
|
||||||
config: {
|
|
||||||
calculation: {
|
|
||||||
calculator: 'add',
|
|
||||||
operands: [
|
|
||||||
{
|
|
||||||
type: '$jobsMapByNodeId',
|
|
||||||
options: {
|
|
||||||
nodeId: 0,
|
|
||||||
path: 'data.read'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: `{{$jobsMapByNodeId.0.data.read}}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { status } = await agent.resource(`workflows`).revision({
|
|
||||||
filterByTk: w1.id
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(status).toBe(400);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,276 @@
|
|||||||
|
import { MockServer } from '@nocobase/test';
|
||||||
|
import Database from '@nocobase/database';
|
||||||
|
import { getApp } 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('create', () => {
|
||||||
|
// });
|
||||||
|
|
||||||
|
describe('update', () => {
|
||||||
|
it('update unexecuted workflow should be ok', async () => {
|
||||||
|
const workflow = await WorkflowModel.create({
|
||||||
|
enabled: true,
|
||||||
|
type: 'collection',
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'posts'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { status } = await agent.resource('workflows').update({
|
||||||
|
filterByTk: workflow.id,
|
||||||
|
values: {
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'tags'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('update executed workflow should not be ok', async () => {
|
||||||
|
const workflow = await WorkflowModel.create({
|
||||||
|
enabled: true,
|
||||||
|
type: 'collection',
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'posts'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const p1 = await PostRepo.create({ values: { title: 't1' } });
|
||||||
|
const c1 = await workflow.countExecutions();
|
||||||
|
expect(c1).toBe(1);
|
||||||
|
|
||||||
|
const { status } = await agent.resource('workflows').update({
|
||||||
|
filterByTk: workflow.id,
|
||||||
|
values: {
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'tags'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(status).toBe(400);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('only update executed workflow with "enabled" should be ok', async () => {
|
||||||
|
const workflow = await WorkflowModel.create({
|
||||||
|
enabled: true,
|
||||||
|
type: 'collection',
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'posts'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const p1 = await PostRepo.create({ values: { title: 't1' } });
|
||||||
|
const c1 = await workflow.countExecutions();
|
||||||
|
expect(c1).toBe(1);
|
||||||
|
|
||||||
|
const { status } = await agent.resource('workflows').update({
|
||||||
|
filterByTk: workflow.id,
|
||||||
|
values: {
|
||||||
|
enabled: false,
|
||||||
|
key: workflow.key
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(status).toBe(200);
|
||||||
|
|
||||||
|
const p2 = await PostRepo.create({ values: { title: 't2' } });
|
||||||
|
const c2 = await workflow.countExecutions();
|
||||||
|
expect(c2).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('revision', () => {
|
||||||
|
it('create revision', async () => {
|
||||||
|
const w1 = await WorkflowModel.create({
|
||||||
|
enabled: true,
|
||||||
|
type: 'collection',
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'posts'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { body, status } = await agent.resource(`workflows`).revision({
|
||||||
|
filterByTk: w1.id
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
const { data: w2 } = body;
|
||||||
|
expect(w2.config).toMatchObject(w1.config);
|
||||||
|
expect(w2.key).toBe(w1.key);
|
||||||
|
expect(w2.current).toBeFalsy();
|
||||||
|
expect(w2.enabled).toBe(false);
|
||||||
|
|
||||||
|
const p1 = await PostRepo.create({ values: { title: 't1' } });
|
||||||
|
|
||||||
|
await WorkflowModel.update({
|
||||||
|
enabled: true
|
||||||
|
}, {
|
||||||
|
where: {
|
||||||
|
id: w2.id
|
||||||
|
},
|
||||||
|
individualHooks: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const [w1next, w2next] = await WorkflowModel.findAll({
|
||||||
|
order: [['id', 'ASC']]
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(w1next.enabled).toBe(false);
|
||||||
|
expect(w1next.current).toBe(null);
|
||||||
|
expect(w2next.enabled).toBe(true);
|
||||||
|
expect(w2next.current).toBe(true);
|
||||||
|
|
||||||
|
const p2 = await PostRepo.create({ values: { title: 't2' } });
|
||||||
|
|
||||||
|
const [e1] = await w1next.getExecutions();
|
||||||
|
const [e2] = await w2next.getExecutions();
|
||||||
|
expect(e1.key).toBe(e2.key);
|
||||||
|
expect(e1.workflowId).toBe(w1.id);
|
||||||
|
expect(e2.workflowId).toBe(w2.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('revision with nodes', async () => {
|
||||||
|
const w1 = await WorkflowModel.create({
|
||||||
|
enabled: true,
|
||||||
|
type: 'collection',
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'posts'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const n1 = await w1.createNode({
|
||||||
|
type: 'echo'
|
||||||
|
});
|
||||||
|
const n2 = await w1.createNode({
|
||||||
|
type: 'calculation',
|
||||||
|
config: {
|
||||||
|
calculation: {
|
||||||
|
calculator: 'add',
|
||||||
|
operands: [
|
||||||
|
{
|
||||||
|
type: '$jobsMapByNodeId',
|
||||||
|
options: {
|
||||||
|
nodeId: n1.id,
|
||||||
|
path: 'data.read'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: `{{$jobsMapByNodeId.${n1.id}.data.read}}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
upstreamId: n1.id
|
||||||
|
});
|
||||||
|
await n1.setDownstream(n2);
|
||||||
|
|
||||||
|
const { body } = await agent.resource(`workflows`).revision({
|
||||||
|
filterByTk: w1.id
|
||||||
|
});
|
||||||
|
const w2 = await WorkflowModel.findByPk(body.data.id, {
|
||||||
|
include: [
|
||||||
|
'nodes'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const n1_2 = w2.nodes.find(n => !n.upstreamId);
|
||||||
|
const n2_2 = w2.nodes.find(n => !n.downstreamId);
|
||||||
|
|
||||||
|
expect(n1_2.type).toBe('echo');
|
||||||
|
expect(n2_2.type).toBe('calculation');
|
||||||
|
expect(n2_2.config).toMatchObject({
|
||||||
|
calculation: {
|
||||||
|
calculator: 'add',
|
||||||
|
operands: [
|
||||||
|
{
|
||||||
|
type: '$jobsMapByNodeId',
|
||||||
|
options: {
|
||||||
|
nodeId: n1_2.id,
|
||||||
|
path: 'data.read'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: `{{$jobsMapByNodeId.${n1_2.id}.data.read}}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await w2.update({ enabled: true });
|
||||||
|
|
||||||
|
await PostRepo.create({
|
||||||
|
values: { title: 't1', read: 1 }
|
||||||
|
});
|
||||||
|
|
||||||
|
const [execution] = await w2.getExecutions();
|
||||||
|
const [echo, calculation] = await execution.getJobs({ order: [['id', 'ASC']] });
|
||||||
|
expect(calculation.result).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('revision with using of deleted nodes', async () => {
|
||||||
|
const w1 = await WorkflowModel.create({
|
||||||
|
enabled: true,
|
||||||
|
type: 'collection',
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'posts'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const n2 = await w1.createNode({
|
||||||
|
type: 'calculation',
|
||||||
|
config: {
|
||||||
|
calculation: {
|
||||||
|
calculator: 'add',
|
||||||
|
operands: [
|
||||||
|
{
|
||||||
|
type: '$jobsMapByNodeId',
|
||||||
|
options: {
|
||||||
|
nodeId: 0,
|
||||||
|
path: 'data.read'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: `{{$jobsMapByNodeId.0.data.read}}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { status } = await agent.resource(`workflows`).revision({
|
||||||
|
filterByTk: w1.id
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,6 +1,18 @@
|
|||||||
import { Context, utils } from '@nocobase/actions';
|
import actions, { Context, utils } from '@nocobase/actions';
|
||||||
|
import { Repository } from '@nocobase/database';
|
||||||
|
|
||||||
|
export async function update(context: Context, next) {
|
||||||
|
const repository = utils.getRepositoryFromParams(context) as Repository;
|
||||||
|
const { filterByTk, values } = context.action.params;
|
||||||
|
// only enable/disable
|
||||||
|
if (Object.keys(values).sort().join() !== 'enabled,key'){
|
||||||
|
const workflow = await repository.findById(filterByTk);
|
||||||
|
if (workflow.get('executed')) {
|
||||||
|
return context.throw(400, 'executed workflow can not be updated');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actions.update(context, next);
|
||||||
|
}
|
||||||
|
|
||||||
function typeOf(value) {
|
function typeOf(value) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user