fix(plugin-workflow-manual): fix assignees parsing bug (#4125)

This commit is contained in:
Junyi 2024-04-22 17:00:16 +08:00 committed by GitHub
parent ac30ccc63e
commit 3413c6c6d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 144 additions and 3 deletions

View File

@ -28,4 +28,14 @@ describe('evaluators > appendArrayColumn()', () => {
expect(get(scope, 'a.b')).toEqual(a_b);
expect(get(scope, 'a.b.c')).toEqual([1, 2, 3, 4]);
});
it('nested object array', () => {
const scope = {
a: {
b: { c: [{ d: 1 }, { d: 2 }] },
},
};
appendArrayColumn(scope, 'a.b.c.d');
expect(get(scope, 'a.b.c.d')).toEqual([1, 2]);
});
});

View File

@ -93,7 +93,7 @@ export default class extends Instruction {
async run(node, prevJob, processor: Processor) {
const { mode, ...config } = node.config as ManualConfig;
const assignees = [...new Set(processor.getParsedValue(config.assignees, node.id) || [])];
const assignees = [...new Set(processor.getParsedValue(config.assignees, node.id).flat().filter(Boolean))];
const job = await processor.saveJob({
status: JOB_STATUS.PENDING,
@ -124,7 +124,8 @@ export default class extends Instruction {
async resume(node, job, processor: Processor) {
// NOTE: check all users jobs related if all done then continue as parallel
const { assignees = [], mode } = node.config as ManualConfig;
const { mode } = node.config as ManualConfig;
const assignees = [...new Set(processor.getParsedValue(node.config.assignees, node.id).flat().filter(Boolean))];
const UserJobModel = this.workflow.app.db.getModel('users_jobs');
const distribution = await UserJobModel.count({

View File

@ -0,0 +1,127 @@
import Database from '@nocobase/database';
import { EXECUTION_STATUS, JOB_STATUS } from '@nocobase/plugin-workflow';
import { getApp, sleep } from '@nocobase/plugin-workflow-test';
import { MockServer } from '@nocobase/test';
// NOTE: skipped because time is not stable on github ci, but should work in local
describe('workflow > instructions > manual > assignees', () => {
let app: MockServer;
let agent;
let userAgents;
let db: Database;
let PostRepo;
let CommentRepo;
let WorkflowModel;
let workflow;
let UserModel;
let users;
let UserJobModel;
beforeEach(async () => {
app = await getApp({
plugins: ['users', 'auth', 'workflow-manual'],
});
// await app.getPlugin('auth').install();
agent = app.agent();
db = app.db;
WorkflowModel = db.getCollection('workflows').model;
PostRepo = db.getCollection('posts').repository;
CommentRepo = db.getCollection('comments').repository;
UserModel = db.getCollection('users').model;
UserJobModel = db.getModel('users_jobs');
users = await UserModel.bulkCreate([
{ id: 2, nickname: 'a' },
{ id: 3, nickname: 'b' },
]);
userAgents = users.map((user) => app.agent().login(user));
workflow = await WorkflowModel.create({
enabled: true,
type: 'collection',
config: {
mode: 1,
collection: 'posts',
appends: ['category', 'category.posts'],
},
});
});
afterEach(() => app.destroy());
describe('multiple', () => {
it('assignees from nested array', async () => {
const n1 = await workflow.createNode({
type: 'manual',
config: {
assignees: [`{{$context.data.category.posts.createdById}}`],
forms: {
f1: {
actions: [{ status: JOB_STATUS.RESOLVED, key: 'resolve' }],
},
},
},
});
const post = await PostRepo.create({
values: { title: 't1', category: { title: 'c1' } },
context: { state: { currentUser: users[0] } },
});
await sleep(500);
const [pending] = await workflow.getExecutions();
expect(pending.status).toBe(EXECUTION_STATUS.STARTED);
const [j1] = await pending.getJobs();
expect(j1.status).toBe(JOB_STATUS.PENDING);
const usersJobs = await UserJobModel.findAll();
expect(usersJobs.length).toBe(1);
expect(usersJobs[0].status).toBe(JOB_STATUS.PENDING);
expect(usersJobs[0].userId).toBe(users[0].id);
expect(usersJobs[0].jobId).toBe(j1.id);
const res1 = await agent.resource('users_jobs').submit({
filterByTk: usersJobs[0].id,
values: { result: { f1: {}, _: 'resolve' } },
});
expect(res1.status).toBe(401);
const res2 = await userAgents[1].resource('users_jobs').submit({
filterByTk: usersJobs[0].id,
values: {
result: { f1: {}, _: 'resolve' },
},
});
expect(res2.status).toBe(403);
const res3 = await userAgents[0].resource('users_jobs').submit({
filterByTk: usersJobs[0].id,
values: {
result: { f1: { a: 1 }, _: 'resolve' },
},
});
expect(res3.status).toBe(202);
await sleep(1000);
const [j2] = await pending.getJobs();
expect(j2.status).toBe(JOB_STATUS.RESOLVED);
expect(j2.result).toEqual({ f1: { a: 1 }, _: 'resolve' });
const usersJobsAfter = await UserJobModel.findAll();
expect(usersJobsAfter.length).toBe(1);
expect(usersJobsAfter[0].status).toBe(JOB_STATUS.RESOLVED);
expect(usersJobsAfter[0].result).toEqual({ f1: { a: 1 }, _: 'resolve' });
const res4 = await userAgents[0].resource('users_jobs').submit({
filterByTk: usersJobs[0].id,
values: {
result: { f1: { a: 2 }, _: 'resolve' },
},
});
expect(res4.status).toBe(400);
});
});
});

View File

@ -50,7 +50,10 @@ export async function submit(context: Context, next) {
await processor.prepare();
// NOTE: validate assignee
const assignees = processor.getParsedValue(userJob.node.config.assignees ?? [], userJob.nodeId);
const assignees = processor
.getParsedValue(userJob.node.config.assignees ?? [], userJob.nodeId)
.flat()
.filter(Boolean);
if (!assignees.includes(currentUser.id) || userJob.userId !== currentUser.id) {
return context.throw(403);
}