tachybase_todo/packages/plugins/@nocobase/plugin-workflow-action-trigger/src/server/ActionTrigger.ts
Junyi d691e4c7e6
feat(plugin-workflow): support multiple data source in workflow (#3739)
* feat(plugin-workflow): support multiple data source in workflow

* fix(plugin-workflow): fix test cases

* test(plugin-workflow-sql): debug test case

* fix(plugin-workflow): fix collection trigger creation without config

* test(plugin-workflow-sql): debug test case

* fix: workflow e2e test

* chore(ci): disable console intercept in vitest

* chore(ci): disable console intercept in vitest

* chore(ci): disable console intercept in vitest

* chore(ci): disable console intercept in vitest

* test(plugin-workflow-sql): debug test case

* test: approval e2e

* fix: remove pro-plugins from packages

* refactor(plugin-workflow): support pass collection from props to CollectionBlockInitializer

* test(plugin-workflow): add test case

* fix(plugin-workflow): disable modification of executed workflow

* fix: e2ePageObjectModel

* fix: load data source when data source load failed (#3793)

* chore: console.log

* fix(subTable): fix sorting rule setting (#3795)

* fix: through collection support search (#3800)

* fix(client): visible -> useVisible

* fix(client): fix action designer error occured in custom form (#3801)

* fix(client): fix action designer error occured in custom form

* fix(client): fix from the source

* chore(module): remove submodule

* fix(plugin-workflow): fix client cycling import

* fix(plugin-workflow): fix collection event name

* fix(plugin-workflow): fix undefined ref

---------

Co-authored-by: hongboji <j414562100@qq.com>
Co-authored-by: ChengLei Shao <chareice@live.com>
Co-authored-by: Zeke Zhang <958414905@qq.com>
Co-authored-by: katherinehhh <shunai.tang@hand-china.com>
Co-authored-by: chenos <chenlinxh@gmail.com>
2024-03-25 14:46:22 +08:00

156 lines
4.9 KiB
TypeScript

import { get } from 'lodash';
import { BelongsTo, HasOne } from 'sequelize';
import { Model, modelAssociationByKey } from '@nocobase/database';
import Application, { DefaultContext } from '@nocobase/server';
import { Context as ActionContext, Next } from '@nocobase/actions';
import WorkflowPlugin, { Trigger, WorkflowModel, toJSON } from '@nocobase/plugin-workflow';
import { parseCollectionName } from '@nocobase/data-source-manager';
interface Context extends ActionContext, DefaultContext {}
export default class extends Trigger {
constructor(workflow: WorkflowPlugin) {
super(workflow);
workflow.app.use(this.middleware, { after: 'dataSource' });
}
async triggerAction(context: Context, next: Next) {
const { triggerWorkflows } = context.action.params;
if (!triggerWorkflows) {
return context.throw(400);
}
context.status = 202;
await next();
this.trigger(context);
}
middleware = async (context: Context, next: Next) => {
const {
resourceName,
actionName,
params: { triggerWorkflows },
} = context.action;
if (resourceName === 'workflows' && actionName === 'trigger') {
return this.triggerAction(context, next);
}
await next();
if (!triggerWorkflows) {
return;
}
if (!['create', 'update'].includes(actionName)) {
return;
}
return this.trigger(context);
};
private async trigger(context: Context) {
const { triggerWorkflows = '', values } = context.action.params;
const dataSourceHeader = context.get('x-data-source') || 'main';
const { currentUser, currentRole } = context.state;
const { model: UserModel } = this.workflow.db.getCollection('users');
const userInfo = {
user: UserModel.build(currentUser).desensitize(),
roleName: currentRole,
};
const triggers = triggerWorkflows.split(',').map((trigger) => trigger.split('!'));
const workflowRepo = this.workflow.db.getRepository('workflows');
const workflows = (
await workflowRepo.find({
filter: {
key: triggers.map((trigger) => trigger[0]),
current: true,
type: 'action',
enabled: true,
},
})
).filter((workflow) => Boolean(workflow.config.collection));
const syncGroup = [];
const asyncGroup = [];
for (const workflow of workflows) {
const { collection, appends = [] } = workflow.config;
const [dataSourceName, collectionName] = parseCollectionName(collection);
const trigger = triggers.find((trigger) => trigger[0] == workflow.key);
const event = [workflow];
if (context.action.resourceName !== 'workflows') {
if (!context.body) {
continue;
}
if (dataSourceName !== dataSourceHeader) {
continue;
}
const { body: data } = context;
for (const row of Array.isArray(data) ? data : [data]) {
let payload = row;
if (trigger[1]) {
const paths = trigger[1].split('.');
for (const field of paths) {
if (payload.get(field)) {
payload = payload.get(field);
} else {
const association = <HasOne | BelongsTo>modelAssociationByKey(payload, field);
payload = await payload[association.accessors.get]();
}
}
}
const model = payload.constructor;
if (payload instanceof Model) {
if (collectionName !== model.collection.name) {
continue;
}
if (appends.length) {
payload = await model.collection.repository.findOne({
filterByTk: payload.get(model.primaryKeyAttribute),
appends,
});
}
}
// this.workflow.trigger(workflow, { data: toJSON(payload), ...userInfo });
event.push({ data: toJSON(payload), ...userInfo });
}
} else {
const { model, repository } = (<Application>context.app).dataSourceManager.dataSources
.get(dataSourceName)
.collectionManager.getCollection(collectionName);
let data = trigger[1] ? get(values, trigger[1]) : values;
const pk = get(data, model.primaryKeyAttribute);
if (appends.length && pk != null) {
data = await repository.findOne({
filterByTk: pk,
appends,
});
}
// this.workflow.trigger(workflow, {
// data,
// ...userInfo,
// });
event.push({ data, ...userInfo });
}
(workflow.sync ? syncGroup : asyncGroup).push(event);
}
for (const event of syncGroup) {
await this.workflow.trigger(event[0], event[1], { httpContext: context });
}
for (const event of asyncGroup) {
this.workflow.trigger(event[0], event[1]);
}
}
on(workflow: WorkflowModel) {}
off(workflow: WorkflowModel) {}
}