@nocobase/app-plugin-office-flows-example 0.0.0-stage → 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/README.md +55 -2
- package/dist/client/components/flow-ui.d.ts +111 -0
- package/dist/client/components/flow-ui.d.ts.map +1 -0
- package/dist/client/components/flow-ui.js +175 -0
- package/dist/client/components/flow-ui.js.map +1 -0
- package/dist/client/components/page-container.d.ts +4 -0
- package/dist/client/components/page-container.d.ts.map +1 -0
- package/dist/client/components/page-container.js +6 -0
- package/dist/client/components/page-container.js.map +1 -0
- package/dist/client/components/page-header.d.ts +8 -0
- package/dist/client/components/page-header.d.ts.map +1 -0
- package/dist/client/components/page-header.js +5 -0
- package/dist/client/components/page-header.js.map +1 -0
- package/dist/client/components/ui/badge.d.ts +7 -0
- package/dist/client/components/ui/badge.d.ts.map +1 -0
- package/dist/client/components/ui/badge.js +19 -0
- package/dist/client/components/ui/badge.js.map +1 -0
- package/dist/client/components/ui/button.d.ts +8 -0
- package/dist/client/components/ui/button.d.ts.map +1 -0
- package/dist/client/components/ui/button.js +25 -0
- package/dist/client/components/ui/button.js.map +1 -0
- package/dist/client/components/ui/card.d.ts +11 -0
- package/dist/client/components/ui/card.d.ts.map +1 -0
- package/dist/client/components/ui/card.js +19 -0
- package/dist/client/components/ui/card.js.map +1 -0
- package/dist/client/components/ui/input.d.ts +4 -0
- package/dist/client/components/ui/input.d.ts.map +1 -0
- package/dist/client/components/ui/input.js +8 -0
- package/dist/client/components/ui/input.js.map +1 -0
- package/dist/client/components/ui/select.d.ts +16 -0
- package/dist/client/components/ui/select.d.ts.map +1 -0
- package/dist/client/components/ui/select.js +36 -0
- package/dist/client/components/ui/select.js.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/lib/api.d.ts +93 -0
- package/dist/client/lib/api.d.ts.map +1 -0
- package/dist/client/lib/api.js +67 -0
- package/dist/client/lib/api.js.map +1 -0
- package/dist/client/lib/format.d.ts +4 -0
- package/dist/client/lib/format.d.ts.map +1 -0
- package/dist/client/lib/format.js +8 -0
- package/dist/client/lib/format.js.map +1 -0
- package/dist/client/lib/labels.d.ts +5 -0
- package/dist/client/lib/labels.d.ts.map +1 -0
- package/dist/client/lib/labels.js +38 -0
- package/dist/client/lib/labels.js.map +1 -0
- package/dist/client/lib/use-loader.d.ts +10 -0
- package/dist/client/lib/use-loader.d.ts.map +1 -0
- package/dist/client/lib/use-loader.js +43 -0
- package/dist/client/lib/use-loader.js.map +1 -0
- package/dist/client/lib/utils.d.ts +2 -0
- package/dist/client/lib/utils.d.ts.map +1 -0
- package/dist/client/lib/utils.js +2 -0
- package/dist/client/lib/utils.js.map +1 -0
- package/dist/client/locales/en-US.d.ts +99 -0
- package/dist/client/locales/en-US.d.ts.map +1 -0
- package/dist/client/locales/en-US.js +92 -0
- package/dist/client/locales/en-US.js.map +1 -0
- package/dist/client/locales/index.d.ts +4 -0
- package/dist/client/locales/index.d.ts.map +1 -0
- package/dist/client/locales/index.js +7 -0
- package/dist/client/locales/index.js.map +1 -0
- package/dist/client/locales/zh-CN.d.ts +4 -0
- package/dist/client/locales/zh-CN.d.ts.map +1 -0
- package/dist/client/locales/zh-CN.js +92 -0
- package/dist/client/locales/zh-CN.js.map +1 -0
- package/dist/client/pages/configuration.d.ts +4 -0
- package/dist/client/pages/configuration.d.ts.map +1 -0
- package/dist/client/pages/configuration.js +34 -0
- package/dist/client/pages/configuration.js.map +1 -0
- package/dist/client/pages/data-requests.d.ts +3 -0
- package/dist/client/pages/data-requests.d.ts.map +1 -0
- package/dist/client/pages/data-requests.js +216 -0
- package/dist/client/pages/data-requests.js.map +1 -0
- package/dist/client/pages/incoming.d.ts +3 -0
- package/dist/client/pages/incoming.d.ts.map +1 -0
- package/dist/client/pages/incoming.js +128 -0
- package/dist/client/pages/incoming.js.map +1 -0
- package/dist/client/pages/tasks.d.ts +3 -0
- package/dist/client/pages/tasks.d.ts.map +1 -0
- package/dist/client/pages/tasks.js +116 -0
- package/dist/client/pages/tasks.js.map +1 -0
- package/dist/client/plugin.d.ts +4 -0
- package/dist/client/plugin.d.ts.map +1 -0
- package/dist/client/plugin.js +10 -0
- package/dist/client/plugin.js.map +1 -0
- package/dist/client/routes.d.ts +4 -0
- package/dist/client/routes.d.ts.map +1 -0
- package/dist/client/routes.js +51 -0
- package/dist/client/routes.js.map +1 -0
- package/dist/database/migrations/.manifest.json +9 -0
- package/dist/database/migrations/202610010001_office_flows_example_create_collections.d.ts +4 -0
- package/dist/database/migrations/202610010001_office_flows_example_create_collections.d.ts.map +1 -0
- package/dist/database/migrations/202610010001_office_flows_example_create_collections.js +280 -0
- package/dist/database/migrations/202610010001_office_flows_example_create_collections.js.map +1 -0
- package/dist/database/seeds/.manifest.json +9 -0
- package/dist/database/seeds/202610010002_office_flows_example_seed_configuration.d.ts +10 -0
- package/dist/database/seeds/202610010002_office_flows_example_seed_configuration.d.ts.map +1 -0
- package/dist/database/seeds/202610010002_office_flows_example_seed_configuration.js +104 -0
- package/dist/database/seeds/202610010002_office_flows_example_seed_configuration.js.map +1 -0
- package/dist/server/calendar.d.ts +35 -0
- package/dist/server/calendar.d.ts.map +1 -0
- package/dist/server/calendar.js +103 -0
- package/dist/server/calendar.js.map +1 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lifecycles/data-request.d.ts +36 -0
- package/dist/server/lifecycles/data-request.d.ts.map +1 -0
- package/dist/server/lifecycles/data-request.js +182 -0
- package/dist/server/lifecycles/data-request.js.map +1 -0
- package/dist/server/lifecycles/extraction.d.ts +21 -0
- package/dist/server/lifecycles/extraction.d.ts.map +1 -0
- package/dist/server/lifecycles/extraction.js +60 -0
- package/dist/server/lifecycles/extraction.js.map +1 -0
- package/dist/server/lifecycles/incoming.d.ts +27 -0
- package/dist/server/lifecycles/incoming.d.ts.map +1 -0
- package/dist/server/lifecycles/incoming.js +177 -0
- package/dist/server/lifecycles/incoming.js.map +1 -0
- package/dist/server/lifecycles/index.d.ts +8 -0
- package/dist/server/lifecycles/index.d.ts.map +1 -0
- package/dist/server/lifecycles/index.js +20 -0
- package/dist/server/lifecycles/index.js.map +1 -0
- package/dist/server/lifecycles/tasks.d.ts +63 -0
- package/dist/server/lifecycles/tasks.d.ts.map +1 -0
- package/dist/server/lifecycles/tasks.js +259 -0
- package/dist/server/lifecycles/tasks.js.map +1 -0
- package/dist/server/plugin.d.ts +4 -0
- package/dist/server/plugin.d.ts.map +1 -0
- package/dist/server/plugin.js +16 -0
- package/dist/server/plugin.js.map +1 -0
- package/dist/server/providers/index.d.ts +4 -0
- package/dist/server/providers/index.d.ts.map +1 -0
- package/dist/server/providers/index.js +6 -0
- package/dist/server/providers/index.js.map +1 -0
- package/dist/server/providers/office-flows.d.ts +23 -0
- package/dist/server/providers/office-flows.d.ts.map +1 -0
- package/dist/server/providers/office-flows.js +90 -0
- package/dist/server/providers/office-flows.js.map +1 -0
- package/dist/server/routes/index.d.ts +8 -0
- package/dist/server/routes/index.d.ts.map +1 -0
- package/dist/server/routes/index.js +553 -0
- package/dist/server/routes/index.js.map +1 -0
- package/dist/server/routes/schemas.d.ts +157 -0
- package/dist/server/routes/schemas.d.ts.map +1 -0
- package/dist/server/routes/schemas.js +188 -0
- package/dist/server/routes/schemas.js.map +1 -0
- package/dist/server/scope.d.ts +23 -0
- package/dist/server/scope.d.ts.map +1 -0
- package/dist/server/scope.js +23 -0
- package/dist/server/scope.js.map +1 -0
- package/dist/server/services/office-flows.d.ts +151 -0
- package/dist/server/services/office-flows.d.ts.map +1 -0
- package/dist/server/services/office-flows.js +603 -0
- package/dist/server/services/office-flows.js.map +1 -0
- package/dist/server/services/store.d.ts +119 -0
- package/dist/server/services/store.d.ts.map +1 -0
- package/dist/server/services/store.js +389 -0
- package/dist/server/services/store.js.map +1 -0
- package/dist/server/tokens.d.ts +4 -0
- package/dist/server/tokens.d.ts.map +1 -0
- package/dist/server/tokens.js +3 -0
- package/dist/server/tokens.js.map +1 -0
- package/dist/shared/data-request.d.ts +73 -0
- package/dist/shared/data-request.d.ts.map +1 -0
- package/dist/shared/data-request.js +182 -0
- package/dist/shared/data-request.js.map +1 -0
- package/dist/shared/fields.d.ts +12 -0
- package/dist/shared/fields.d.ts.map +1 -0
- package/dist/shared/fields.js +48 -0
- package/dist/shared/fields.js.map +1 -0
- package/dist/shared/people.d.ts +29 -0
- package/dist/shared/people.d.ts.map +1 -0
- package/dist/shared/people.js +54 -0
- package/dist/shared/people.js.map +1 -0
- package/dist/shared/routes.d.ts +7 -0
- package/dist/shared/routes.d.ts.map +1 -0
- package/dist/shared/routes.js +7 -0
- package/dist/shared/routes.js.map +1 -0
- package/dist/shared/text.d.ts +3 -0
- package/dist/shared/text.d.ts.map +1 -0
- package/dist/shared/text.js +9 -0
- package/dist/shared/text.js.map +1 -0
- package/package.json +72 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-flows.d.ts","sourceRoot":"","sources":["../../../server/providers/office-flows.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAUzE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAQ7D,2EAA2E;AAC3E,eAAO,MAAM,QAAQ,EAAE,MAAe,CAAC;AAEvC;;;;;;GAMG;AACH,qBAAa,mBAAoB,SAAQ,eAAe,CAAC,oBAAoB,CAAC;IAC5E,SAAgB,IAAI,EAAE,MAAM,CAAsB;IAClD,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,OAAO,CAA+B;IAE9B,QAAQ,IAAI,IAAI;IAWV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/C,OAAO,CAAC,gBAAgB;IAwBxB,+DAA+D;IAC/D,OAAO,CAAC,UAAU;CA0BnB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { jobExecutorServiceToken } from '@nocobase/app-server/jobs';
|
|
2
|
+
import { loggingToken } from '@nocobase/app-server/logging';
|
|
3
|
+
import { databaseManagerToken } from '@nocobase/db';
|
|
4
|
+
import { createRepositoryLifecycleStore, LifecycleRuntime, } from '@nocobase/lifecycle';
|
|
5
|
+
import { createLifecycleJobs, } from '@nocobase/lifecycle/jobs';
|
|
6
|
+
import { ServiceProvider } from '@nocobase/service-provider';
|
|
7
|
+
import { registerLifecycles } from '../lifecycles/index.js';
|
|
8
|
+
import { COLLECTIONS, OFFICE_FLOWS_SCOPE } from '../scope.js';
|
|
9
|
+
import { OfficeFlowsService } from '../services/office-flows.js';
|
|
10
|
+
import { OfficeStore } from '../services/store.js';
|
|
11
|
+
import { officeFlowsServiceToken } from '../tokens.js';
|
|
12
|
+
/** How often idle records are checked and due extraction tasks created. */
|
|
13
|
+
export const SWEEP_MS = 60_000;
|
|
14
|
+
/**
|
|
15
|
+
* Wires the six lifecycles to the application through `createLifecycleJobs()`:
|
|
16
|
+
* effects as jobs on a JobExecutor, and one ScheduleExecutor rule that sweeps
|
|
17
|
+
* the triggers and creates the extraction tasks falling due. A real
|
|
18
|
+
* deployment would sweep once a day; the example sweeps every minute so a new
|
|
19
|
+
* request shows its first task without waiting.
|
|
20
|
+
*/
|
|
21
|
+
export class OfficeFlowsProvider extends ServiceProvider {
|
|
22
|
+
name = OFFICE_FLOWS_SCOPE;
|
|
23
|
+
jobs;
|
|
24
|
+
runtime;
|
|
25
|
+
register() {
|
|
26
|
+
this.app.container.singleton(officeFlowsServiceToken, () => {
|
|
27
|
+
const database = this.app.container.resolve(databaseManagerToken);
|
|
28
|
+
return new OfficeFlowsService(database, this.lifecycleRuntime(), new OfficeStore(database));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async start() {
|
|
32
|
+
await this.effectJobs().start(this.lifecycleRuntime());
|
|
33
|
+
}
|
|
34
|
+
async shutdown() {
|
|
35
|
+
await this.jobs?.shutdown();
|
|
36
|
+
this.jobs = undefined;
|
|
37
|
+
}
|
|
38
|
+
lifecycleRuntime() {
|
|
39
|
+
if (this.runtime)
|
|
40
|
+
return this.runtime;
|
|
41
|
+
const database = this.app.container.resolve(databaseManagerToken);
|
|
42
|
+
const logger = this.app.container
|
|
43
|
+
.resolve(loggingToken)
|
|
44
|
+
.getLogger('office-flows-example');
|
|
45
|
+
const runtime = new LifecycleRuntime({
|
|
46
|
+
store: createRepositoryLifecycleStore(database, {
|
|
47
|
+
collections: {
|
|
48
|
+
transitions: COLLECTIONS.transitions,
|
|
49
|
+
effectRuns: COLLECTIONS.effectRuns,
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
52
|
+
dispatcher: this.effectJobs(),
|
|
53
|
+
logger: {
|
|
54
|
+
warn: (message, details) => logger.warn({ details }, message),
|
|
55
|
+
error: (message, details) => logger.error({ details }, message),
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
registerLifecycles(runtime, new OfficeStore(database));
|
|
59
|
+
this.runtime = runtime;
|
|
60
|
+
return runtime;
|
|
61
|
+
}
|
|
62
|
+
/** The dispatcher, created before the runtime that uses it. */
|
|
63
|
+
effectJobs() {
|
|
64
|
+
if (this.jobs)
|
|
65
|
+
return this.jobs;
|
|
66
|
+
const executors = this.app.container.resolve(jobExecutorServiceToken);
|
|
67
|
+
const logger = this.app.container
|
|
68
|
+
.resolve(loggingToken)
|
|
69
|
+
.getLogger('office-flows-example');
|
|
70
|
+
this.jobs = createLifecycleJobs({
|
|
71
|
+
jobs: executors.getJobExecutor(OFFICE_FLOWS_SCOPE),
|
|
72
|
+
schedule: executors.getScheduleExecutor(OFFICE_FLOWS_SCOPE),
|
|
73
|
+
// Stored with every queued task: keep it stable.
|
|
74
|
+
jobName: `${OFFICE_FLOWS_SCOPE}/effect`,
|
|
75
|
+
sweepName: 'sweep',
|
|
76
|
+
sweepEveryMs: SWEEP_MS,
|
|
77
|
+
// The extraction tasks due today, after the triggers have run.
|
|
78
|
+
onSweep: () => this.app.container
|
|
79
|
+
.resolve(officeFlowsServiceToken)
|
|
80
|
+
.runSchedule()
|
|
81
|
+
.then(() => undefined),
|
|
82
|
+
logger: {
|
|
83
|
+
warn: (message, details) => logger.warn({ details }, message),
|
|
84
|
+
error: (message, details) => logger.error({ details }, message),
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
return this.jobs;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=office-flows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"office-flows.js","sourceRoot":"","sources":["../../../server/providers/office-flows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EACL,8BAA8B,EAC9B,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,mBAAmB,GAEpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEvD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,QAAQ,GAAW,MAAM,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,OAAO,mBAAoB,SAAQ,eAAqC;IAC5D,IAAI,GAAW,kBAAkB,CAAC;IAC1C,IAAI,CAA4B;IAChC,OAAO,CAA+B;IAE9B,QAAQ;QACtB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,uBAAuB,EAAE,GAAG,EAAE;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;YAClE,OAAO,IAAI,kBAAkB,CAC3B,QAAQ,EACR,IAAI,CAAC,gBAAgB,EAAE,EACvB,IAAI,WAAW,CAAC,QAAQ,CAAC,CAC1B,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEe,KAAK,CAAC,KAAK;QACzB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACzD,CAAC;IAEe,KAAK,CAAC,QAAQ;QAC5B,MAAM,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;IACxB,CAAC;IAEO,gBAAgB;QACtB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS;aAC9B,OAAO,CAAC,YAAY,CAAC;aACrB,SAAS,CAAC,sBAAsB,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC;YACnC,KAAK,EAAE,8BAA8B,CAAC,QAAQ,EAAE;gBAC9C,WAAW,EAAE;oBACX,WAAW,EAAE,WAAW,CAAC,WAAW;oBACpC,UAAU,EAAE,WAAW,CAAC,UAAU;iBACnC;aACF,CAAC;YACF,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;YAC7B,MAAM,EAAE;gBACN,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC;gBAC7D,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC;aAChE;SACF,CAAC,CAAC;QACH,kBAAkB,CAAC,OAAO,EAAE,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,+DAA+D;IACvD,UAAU;QAChB,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS;aAC9B,OAAO,CAAC,YAAY,CAAC;aACrB,SAAS,CAAC,sBAAsB,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;YAC9B,IAAI,EAAE,SAAS,CAAC,cAAc,CAAC,kBAAkB,CAAC;YAClD,QAAQ,EAAE,SAAS,CAAC,mBAAmB,CAAC,kBAAkB,CAAC;YAC3D,iDAAiD;YACjD,OAAO,EAAE,GAAG,kBAAkB,SAAS;YACvC,SAAS,EAAE,OAAO;YAClB,YAAY,EAAE,QAAQ;YACtB,+DAA+D;YAC/D,OAAO,EAAE,GAAG,EAAE,CACZ,IAAI,CAAC,GAAG,CAAC,SAAS;iBACf,OAAO,CAAC,uBAAuB,CAAC;iBAChC,WAAW,EAAE;iBACb,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;YAC1B,MAAM,EAAE;gBACN,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC;gBAC7D,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC;aAChE;SACF,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AppPluginApplication } from '@nocobase/app-server/plugins';
|
|
2
|
+
import { type AppApiRouteContribution } from '@nocobase/app-server/router';
|
|
3
|
+
/** The namespace of every route this plugin owns, and the domain of its errors. */
|
|
4
|
+
export declare const OFFICE_FLOWS_DOMAIN: string;
|
|
5
|
+
export declare const apiRoutes: AppApiRouteContribution<AppPluginApplication>;
|
|
6
|
+
declare const routes: readonly AppApiRouteContribution<AppPluginApplication>[];
|
|
7
|
+
export default routes;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../server/routes/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAWL,KAAK,uBAAuB,EAC7B,MAAM,6BAA6B,CAAC;AAsCrC,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,EAAE,MAA4B,CAAC;AAoH/D,eAAO,MAAM,SAAS,EAAE,uBAAuB,CAAC,oBAAoB,CA4tBhE,CAAC;AAEL,QAAA,MAAM,MAAM,EAAE,SAAS,uBAAuB,CAAC,oBAAoB,CAAC,EAEnE,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { authenticationToken, } from '@nocobase/app-plugin-authentication';
|
|
2
|
+
import { ApiError, apiErrorHandler, apiErrorResponse, apiValidator, dataResponse, defineApiRoutes, describeRoute, emptyResponse, listResponse, } from '@nocobase/app-server/router';
|
|
3
|
+
import { LifecycleError, lifecycleErrorFields } from '@nocobase/lifecycle';
|
|
4
|
+
import { Hono } from 'hono';
|
|
5
|
+
import { emptyDataRequest, } from '../../shared/data-request.js';
|
|
6
|
+
import { OFFICE_FLOWS_ROUTES } from '../../shared/routes.js';
|
|
7
|
+
import { OfficeFlowsError } from '../services/office-flows.js';
|
|
8
|
+
import { officeFlowsServiceToken } from '../tokens.js';
|
|
9
|
+
import { ActAsPageQuery, ActAsQuery, Created, CreateExtractionInput, DataRequestFormInput, DispatchingTaskParams, ExtractionParams, ExtractionValuesInput, FireInput, IncomingParams, IncomingValuesInput, ManagementRowInput, OfficeConfig, OfficeDetail, OfficeRecord, PageMeta, PageQuery, RequestParams, RowInput, RowParams, ScheduleRun, TaskParams, TaskValuesInput, } from './schemas.js';
|
|
10
|
+
/** The namespace of every route this plugin owns, and the domain of its errors. */
|
|
11
|
+
export const OFFICE_FLOWS_DOMAIN = OFFICE_FLOWS_ROUTES;
|
|
12
|
+
/** Every route below starts here; the client reads the same constant. */
|
|
13
|
+
const BASE = `/${OFFICE_FLOWS_ROUTES}`;
|
|
14
|
+
/** Every route of this plugin is listed under one tag in the API document at `/api/swagger/docs`. */
|
|
15
|
+
const tags = ['OfficeFlowsExample'];
|
|
16
|
+
const SERVICE_STATUS = {
|
|
17
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
18
|
+
FORBIDDEN: 'PERMISSION_DENIED',
|
|
19
|
+
INVALID: 'INVALID_ARGUMENT',
|
|
20
|
+
LOCKED: 'FAILED_PRECONDITION',
|
|
21
|
+
CONFLICT: 'ABORTED',
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The service's refusals and the lifecycles', as the standard error body.
|
|
25
|
+
* `inputField` names where a transition's input sits in the request body.
|
|
26
|
+
*/
|
|
27
|
+
function toApiError(error, inputField) {
|
|
28
|
+
if (error instanceof LifecycleError) {
|
|
29
|
+
const fields = lifecycleErrorFields(error, inputField ? { inputField } : {});
|
|
30
|
+
// A broken definition is the server's fault: the application answers 500.
|
|
31
|
+
return fields
|
|
32
|
+
? new ApiError({ ...fields, domain: OFFICE_FLOWS_DOMAIN })
|
|
33
|
+
: error;
|
|
34
|
+
}
|
|
35
|
+
if (error instanceof OfficeFlowsError)
|
|
36
|
+
return new ApiError({
|
|
37
|
+
status: SERVICE_STATUS[error.code],
|
|
38
|
+
reason: error.reason,
|
|
39
|
+
domain: OFFICE_FLOWS_DOMAIN,
|
|
40
|
+
message: error.message,
|
|
41
|
+
...(error.fields.length
|
|
42
|
+
? {
|
|
43
|
+
fieldViolations: error.fields.map((field) => ({
|
|
44
|
+
field,
|
|
45
|
+
description: error.message,
|
|
46
|
+
})),
|
|
47
|
+
}
|
|
48
|
+
: {}),
|
|
49
|
+
});
|
|
50
|
+
return error;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A value as a response carries it: every id — `id` and each `…Id` — a
|
|
54
|
+
* string, since the collections' integer keys would otherwise reach a
|
|
55
|
+
* client as numbers.
|
|
56
|
+
*/
|
|
57
|
+
function outward(value) {
|
|
58
|
+
if (Array.isArray(value))
|
|
59
|
+
return value.map(outward);
|
|
60
|
+
if (typeof value !== 'object' || value === null)
|
|
61
|
+
return value;
|
|
62
|
+
return Object.fromEntries(Object.entries(value).map(([key, field]) => [
|
|
63
|
+
key,
|
|
64
|
+
(key === 'id' || key.endsWith('Id')) && typeof field === 'number'
|
|
65
|
+
? String(field)
|
|
66
|
+
: outward(field),
|
|
67
|
+
]));
|
|
68
|
+
}
|
|
69
|
+
const data = (value) => ({
|
|
70
|
+
data: outward(value),
|
|
71
|
+
});
|
|
72
|
+
function page(result, query) {
|
|
73
|
+
return {
|
|
74
|
+
data: outward(result.records),
|
|
75
|
+
meta: { page: query.page, pageSize: query.pageSize, total: result.total },
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** A new request's form: a field the request leaves out starts empty. */
|
|
79
|
+
function form(values) {
|
|
80
|
+
return { ...emptyDataRequest(), ...values };
|
|
81
|
+
}
|
|
82
|
+
const noContent = emptyResponse();
|
|
83
|
+
const unauthorized = apiErrorResponse(401);
|
|
84
|
+
const internal = apiErrorResponse(500);
|
|
85
|
+
const notFound = apiErrorResponse(404, 'No such record (`RECORD_NOT_FOUND`).');
|
|
86
|
+
const fireRefusals = {
|
|
87
|
+
400: apiErrorResponse(400, 'The state does not allow it, or the record is not complete enough (`INVALID_STATE`); every guard that refused waits for the record to change (`GUARD_REJECTED`, status `FAILED_PRECONDITION`), such as an open extraction task; its input is invalid (`INVALID_INPUT`) or the transition is unknown (`UNKNOWN_TRANSITION`).'),
|
|
88
|
+
403: apiErrorResponse(403, 'A guard refused the persona while others may still act (`GUARD_REJECTED`), such as a clerk who has already countersigned.'),
|
|
89
|
+
409: apiErrorResponse(409, 'A concurrent change won (`CONFLICT`).'),
|
|
90
|
+
};
|
|
91
|
+
const editRefusals = {
|
|
92
|
+
400: apiErrorResponse(400, 'The record cannot be edited at this step (`RECORD_LOCKED`).'),
|
|
93
|
+
403: apiErrorResponse(403, 'The persona cannot edit it (`EDIT_NOT_ALLOWED`).'),
|
|
94
|
+
409: apiErrorResponse(409, 'Concurrent changes kept winning; the edit was reapplied and gave up (`RECORD_CHANGED`).'),
|
|
95
|
+
};
|
|
96
|
+
export const apiRoutes = defineApiRoutes(({ container }) => {
|
|
97
|
+
const router = new Hono();
|
|
98
|
+
const authentication = container.resolve(authenticationToken);
|
|
99
|
+
const service = container.resolve(officeFlowsServiceToken);
|
|
100
|
+
const fire = async (work) => {
|
|
101
|
+
try {
|
|
102
|
+
await work();
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
// The transition's input sits under `input` in these bodies.
|
|
106
|
+
throw toApiError(error, 'input');
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
router.use(`${BASE}/*`, authentication.required());
|
|
110
|
+
router.onError((error, context) => apiErrorHandler(toApiError(error), context));
|
|
111
|
+
// ── Reference data and the persona's reminders ──────────────────────
|
|
112
|
+
router.get(`${BASE}/config`, describeRoute({
|
|
113
|
+
tags,
|
|
114
|
+
summary: 'Get the reference data',
|
|
115
|
+
operationId: 'officeFlowsExampleGetConfig',
|
|
116
|
+
description: 'The cast and its roles, the departments, the management groups and the holidays.',
|
|
117
|
+
responses: {
|
|
118
|
+
200: dataResponse(OfficeConfig),
|
|
119
|
+
401: unauthorized,
|
|
120
|
+
500: internal,
|
|
121
|
+
},
|
|
122
|
+
}), async (context) => context.json(data(await service.config())));
|
|
123
|
+
router.get(`${BASE}/notices`, describeRoute({
|
|
124
|
+
tags,
|
|
125
|
+
summary: 'List the persona’s reminders',
|
|
126
|
+
operationId: 'officeFlowsExampleListNotices',
|
|
127
|
+
responses: {
|
|
128
|
+
200: listResponse(OfficeRecord, PageMeta),
|
|
129
|
+
401: unauthorized,
|
|
130
|
+
500: internal,
|
|
131
|
+
},
|
|
132
|
+
}), apiValidator('query', ActAsPageQuery), async (context) => {
|
|
133
|
+
const query = context.req.valid('query');
|
|
134
|
+
return context.json(page(await service.notices(query.actAs, query), query));
|
|
135
|
+
});
|
|
136
|
+
router.post(`${BASE}/runSchedule`, describeRoute({
|
|
137
|
+
tags,
|
|
138
|
+
summary: 'Create the extraction tasks that are due',
|
|
139
|
+
operationId: 'officeFlowsExampleRunSchedule',
|
|
140
|
+
description: 'The daily sweep, now: every request in acceptance gets the extraction tasks due by today. Safe to repeat.',
|
|
141
|
+
responses: {
|
|
142
|
+
200: dataResponse(ScheduleRun),
|
|
143
|
+
401: unauthorized,
|
|
144
|
+
500: internal,
|
|
145
|
+
},
|
|
146
|
+
}), async (context) => context.json({ data: { created: await service.runSchedule() } }));
|
|
147
|
+
// ── Data usage requests ─────────────────────────────────────────────
|
|
148
|
+
router.get(`${BASE}/dataRequests`, describeRoute({
|
|
149
|
+
tags,
|
|
150
|
+
summary: 'List data usage requests',
|
|
151
|
+
operationId: 'officeFlowsExampleListDataRequests',
|
|
152
|
+
responses: {
|
|
153
|
+
200: listResponse(OfficeRecord, PageMeta),
|
|
154
|
+
401: unauthorized,
|
|
155
|
+
500: internal,
|
|
156
|
+
},
|
|
157
|
+
}), apiValidator('query', PageQuery), async (context) => {
|
|
158
|
+
const query = context.req.valid('query');
|
|
159
|
+
return context.json(page(await service.listDataRequests(query), query));
|
|
160
|
+
});
|
|
161
|
+
router.post(`${BASE}/dataRequests`, describeRoute({
|
|
162
|
+
tags,
|
|
163
|
+
summary: 'Draft a data usage request',
|
|
164
|
+
operationId: 'officeFlowsExampleCreateDataRequest',
|
|
165
|
+
responses: {
|
|
166
|
+
201: dataResponse(OfficeRecord, 'The request, in `draft`.'),
|
|
167
|
+
401: unauthorized,
|
|
168
|
+
403: apiErrorResponse(403, 'Only the applicant drafts one (`APPLICANT_ONLY`).'),
|
|
169
|
+
500: internal,
|
|
170
|
+
},
|
|
171
|
+
}), apiValidator('query', ActAsQuery), apiValidator('json', DataRequestFormInput), async (context) => {
|
|
172
|
+
const { actAs } = context.req.valid('query');
|
|
173
|
+
const values = context.req.valid('json');
|
|
174
|
+
return context.json(data(await service.createDataRequest(form(values.form), actAs)), 201);
|
|
175
|
+
});
|
|
176
|
+
router.get(`${BASE}/dataRequests/:requestId`, describeRoute({
|
|
177
|
+
tags,
|
|
178
|
+
summary: 'Get a data usage request',
|
|
179
|
+
operationId: 'officeFlowsExampleGetDataRequest',
|
|
180
|
+
responses: {
|
|
181
|
+
200: dataResponse(OfficeDetail),
|
|
182
|
+
401: unauthorized,
|
|
183
|
+
404: notFound,
|
|
184
|
+
500: internal,
|
|
185
|
+
},
|
|
186
|
+
}), apiValidator('param', RequestParams), apiValidator('query', ActAsQuery), async (context) => {
|
|
187
|
+
const { requestId } = context.req.valid('param');
|
|
188
|
+
const { actAs } = context.req.valid('query');
|
|
189
|
+
return context.json(data(await service.dataRequestDetail(requestId, actAs)));
|
|
190
|
+
});
|
|
191
|
+
router.patch(`${BASE}/dataRequests/:requestId`, describeRoute({
|
|
192
|
+
tags,
|
|
193
|
+
summary: 'Edit a draft data usage request',
|
|
194
|
+
operationId: 'officeFlowsExampleUpdateDataRequest',
|
|
195
|
+
description: 'Changes only the form fields sent; the others keep their values. Answers the choices hide are cleared, as on creation.',
|
|
196
|
+
responses: {
|
|
197
|
+
200: dataResponse(OfficeDetail, 'The request as edited.'),
|
|
198
|
+
...editRefusals,
|
|
199
|
+
401: unauthorized,
|
|
200
|
+
404: notFound,
|
|
201
|
+
500: internal,
|
|
202
|
+
},
|
|
203
|
+
}), apiValidator('param', RequestParams), apiValidator('query', ActAsQuery), apiValidator('json', DataRequestFormInput), async (context) => {
|
|
204
|
+
const { requestId } = context.req.valid('param');
|
|
205
|
+
const { actAs } = context.req.valid('query');
|
|
206
|
+
const values = context.req.valid('json');
|
|
207
|
+
// Only the fields sent: the schema adds none, so the rest stay as stored.
|
|
208
|
+
await service.updateDataRequest(requestId, values.form, actAs);
|
|
209
|
+
return context.json(data(await service.dataRequestDetail(requestId, actAs)));
|
|
210
|
+
});
|
|
211
|
+
router.post(`${BASE}/dataRequests/:requestId/fire`, describeRoute({
|
|
212
|
+
tags,
|
|
213
|
+
summary: 'Fire a transition on a data usage request',
|
|
214
|
+
operationId: 'officeFlowsExampleFireDataRequestTransition',
|
|
215
|
+
responses: {
|
|
216
|
+
204: noContent,
|
|
217
|
+
...fireRefusals,
|
|
218
|
+
401: unauthorized,
|
|
219
|
+
404: notFound,
|
|
220
|
+
500: internal,
|
|
221
|
+
},
|
|
222
|
+
}), apiValidator('param', RequestParams), apiValidator('query', ActAsQuery), apiValidator('json', FireInput), async (context) => {
|
|
223
|
+
const { requestId } = context.req.valid('param');
|
|
224
|
+
const { actAs } = context.req.valid('query');
|
|
225
|
+
const { transition, input } = context.req.valid('json');
|
|
226
|
+
await fire(() => service.fire('dataRequests', requestId, transition, input, actAs, true));
|
|
227
|
+
return context.body(null, 204);
|
|
228
|
+
});
|
|
229
|
+
router.post(`${BASE}/dataRequests/:requestId/extractions`, describeRoute({
|
|
230
|
+
tags,
|
|
231
|
+
summary: 'Create an extraction task by hand',
|
|
232
|
+
operationId: 'officeFlowsExampleCreateExtraction',
|
|
233
|
+
description: 'Only the acceptor, while the request is in acceptance; the task takes the next number.',
|
|
234
|
+
responses: {
|
|
235
|
+
201: dataResponse(OfficeRecord, 'The extraction task, `pending`.'),
|
|
236
|
+
400: apiErrorResponse(400, 'No topic or no valid first date (`EXTRACTION_FIELDS_REQUIRED`, with `fieldViolations`).'),
|
|
237
|
+
401: unauthorized,
|
|
238
|
+
403: apiErrorResponse(403, 'Not the acceptor, or not in acceptance (`ACCEPTOR_ONLY`).'),
|
|
239
|
+
404: notFound,
|
|
240
|
+
409: apiErrorResponse(409, 'The request left acceptance meanwhile (`REQUEST_LEFT_ACCEPTANCE`).'),
|
|
241
|
+
500: internal,
|
|
242
|
+
},
|
|
243
|
+
}), apiValidator('param', RequestParams), apiValidator('query', ActAsQuery), apiValidator('json', CreateExtractionInput), async (context) => {
|
|
244
|
+
const { requestId } = context.req.valid('param');
|
|
245
|
+
const { actAs } = context.req.valid('query');
|
|
246
|
+
const values = context.req.valid('json');
|
|
247
|
+
return context.json(data(await service.createManualExtraction(requestId, values, actAs)), 201);
|
|
248
|
+
});
|
|
249
|
+
// ── Extraction tasks ────────────────────────────────────────────────
|
|
250
|
+
router.get(`${BASE}/extractions/:extractionId`, describeRoute({
|
|
251
|
+
tags,
|
|
252
|
+
summary: 'Get an extraction task',
|
|
253
|
+
operationId: 'officeFlowsExampleGetExtraction',
|
|
254
|
+
responses: {
|
|
255
|
+
200: dataResponse(OfficeDetail),
|
|
256
|
+
401: unauthorized,
|
|
257
|
+
404: notFound,
|
|
258
|
+
500: internal,
|
|
259
|
+
},
|
|
260
|
+
}), apiValidator('param', ExtractionParams), apiValidator('query', ActAsQuery), async (context) => {
|
|
261
|
+
const { extractionId } = context.req.valid('param');
|
|
262
|
+
const { actAs } = context.req.valid('query');
|
|
263
|
+
return context.json(data(await service.extractionDetail(extractionId, actAs)));
|
|
264
|
+
});
|
|
265
|
+
router.patch(`${BASE}/extractions/:extractionId`, describeRoute({
|
|
266
|
+
tags,
|
|
267
|
+
summary: 'Edit a pending extraction task',
|
|
268
|
+
operationId: 'officeFlowsExampleUpdateExtraction',
|
|
269
|
+
responses: {
|
|
270
|
+
200: dataResponse(OfficeDetail, 'The task as edited.'),
|
|
271
|
+
...editRefusals,
|
|
272
|
+
401: unauthorized,
|
|
273
|
+
404: notFound,
|
|
274
|
+
500: internal,
|
|
275
|
+
},
|
|
276
|
+
}), apiValidator('param', ExtractionParams), apiValidator('query', ActAsQuery), apiValidator('json', ExtractionValuesInput), async (context) => {
|
|
277
|
+
const { extractionId } = context.req.valid('param');
|
|
278
|
+
const { actAs } = context.req.valid('query');
|
|
279
|
+
const { values } = context.req.valid('json');
|
|
280
|
+
await service.updateExtraction(extractionId, values, actAs);
|
|
281
|
+
return context.json(data(await service.extractionDetail(extractionId, actAs)));
|
|
282
|
+
});
|
|
283
|
+
router.post(`${BASE}/extractions/:extractionId/fire`, describeRoute({
|
|
284
|
+
tags,
|
|
285
|
+
summary: 'Fire a transition on an extraction task',
|
|
286
|
+
operationId: 'officeFlowsExampleFireExtractionTransition',
|
|
287
|
+
responses: {
|
|
288
|
+
204: noContent,
|
|
289
|
+
...fireRefusals,
|
|
290
|
+
401: unauthorized,
|
|
291
|
+
404: notFound,
|
|
292
|
+
500: internal,
|
|
293
|
+
},
|
|
294
|
+
}), apiValidator('param', ExtractionParams), apiValidator('query', ActAsQuery), apiValidator('json', FireInput), async (context) => {
|
|
295
|
+
const { extractionId } = context.req.valid('param');
|
|
296
|
+
const { actAs } = context.req.valid('query');
|
|
297
|
+
const { transition, input } = context.req.valid('json');
|
|
298
|
+
await fire(() => service.fire('extractions', extractionId, transition, input, actAs, true));
|
|
299
|
+
return context.body(null, 204);
|
|
300
|
+
});
|
|
301
|
+
// ── Incoming documents ──────────────────────────────────────────────
|
|
302
|
+
router.get(`${BASE}/incoming`, describeRoute({
|
|
303
|
+
tags,
|
|
304
|
+
summary: 'List incoming documents',
|
|
305
|
+
operationId: 'officeFlowsExampleListIncoming',
|
|
306
|
+
responses: {
|
|
307
|
+
200: listResponse(OfficeRecord, PageMeta),
|
|
308
|
+
401: unauthorized,
|
|
309
|
+
500: internal,
|
|
310
|
+
},
|
|
311
|
+
}), apiValidator('query', PageQuery), async (context) => {
|
|
312
|
+
const query = context.req.valid('query');
|
|
313
|
+
return context.json(page(await service.listIncoming(query), query));
|
|
314
|
+
});
|
|
315
|
+
router.post(`${BASE}/incoming`, describeRoute({
|
|
316
|
+
tags,
|
|
317
|
+
summary: 'Record an incoming document',
|
|
318
|
+
operationId: 'officeFlowsExampleCreateIncoming',
|
|
319
|
+
responses: {
|
|
320
|
+
201: dataResponse(OfficeRecord, 'The document, in `draft`.'),
|
|
321
|
+
401: unauthorized,
|
|
322
|
+
403: apiErrorResponse(403, 'Only the office registrar records one (`REGISTRAR_ONLY`).'),
|
|
323
|
+
500: internal,
|
|
324
|
+
},
|
|
325
|
+
}), apiValidator('query', ActAsQuery), apiValidator('json', IncomingValuesInput), async (context) => {
|
|
326
|
+
const { actAs } = context.req.valid('query');
|
|
327
|
+
const { values } = context.req.valid('json');
|
|
328
|
+
return context.json(data(await service.createIncoming(values, actAs)), 201);
|
|
329
|
+
});
|
|
330
|
+
router.get(`${BASE}/incoming/:incomingId`, describeRoute({
|
|
331
|
+
tags,
|
|
332
|
+
summary: 'Get an incoming document',
|
|
333
|
+
operationId: 'officeFlowsExampleGetIncoming',
|
|
334
|
+
responses: {
|
|
335
|
+
200: dataResponse(OfficeDetail),
|
|
336
|
+
401: unauthorized,
|
|
337
|
+
404: notFound,
|
|
338
|
+
500: internal,
|
|
339
|
+
},
|
|
340
|
+
}), apiValidator('param', IncomingParams), apiValidator('query', ActAsQuery), async (context) => {
|
|
341
|
+
const { incomingId } = context.req.valid('param');
|
|
342
|
+
const { actAs } = context.req.valid('query');
|
|
343
|
+
return context.json(data(await service.incomingDetail(incomingId, actAs)));
|
|
344
|
+
});
|
|
345
|
+
router.patch(`${BASE}/incoming/:incomingId`, describeRoute({
|
|
346
|
+
tags,
|
|
347
|
+
summary: 'Edit a draft incoming document',
|
|
348
|
+
operationId: 'officeFlowsExampleUpdateIncoming',
|
|
349
|
+
responses: {
|
|
350
|
+
200: dataResponse(OfficeDetail, 'The document as edited.'),
|
|
351
|
+
...editRefusals,
|
|
352
|
+
401: unauthorized,
|
|
353
|
+
404: notFound,
|
|
354
|
+
500: internal,
|
|
355
|
+
},
|
|
356
|
+
}), apiValidator('param', IncomingParams), apiValidator('query', ActAsQuery), apiValidator('json', IncomingValuesInput), async (context) => {
|
|
357
|
+
const { incomingId } = context.req.valid('param');
|
|
358
|
+
const { actAs } = context.req.valid('query');
|
|
359
|
+
const { values } = context.req.valid('json');
|
|
360
|
+
await service.updateIncoming(incomingId, values, actAs);
|
|
361
|
+
return context.json(data(await service.incomingDetail(incomingId, actAs)));
|
|
362
|
+
});
|
|
363
|
+
router.post(`${BASE}/incoming/:incomingId/fire`, describeRoute({
|
|
364
|
+
tags,
|
|
365
|
+
summary: 'Fire a transition on an incoming document',
|
|
366
|
+
operationId: 'officeFlowsExampleFireIncomingTransition',
|
|
367
|
+
description: 'A dispatch carries the rows pending now, so a retried click sends the same ones.',
|
|
368
|
+
responses: {
|
|
369
|
+
204: noContent,
|
|
370
|
+
...fireRefusals,
|
|
371
|
+
401: unauthorized,
|
|
372
|
+
404: notFound,
|
|
373
|
+
500: internal,
|
|
374
|
+
},
|
|
375
|
+
}), apiValidator('param', IncomingParams), apiValidator('query', ActAsQuery), apiValidator('json', FireInput), async (context) => {
|
|
376
|
+
const { incomingId } = context.req.valid('param');
|
|
377
|
+
const { actAs } = context.req.valid('query');
|
|
378
|
+
const { transition, input } = context.req.valid('json');
|
|
379
|
+
await fire(() => service.fireIncoming(incomingId, transition, input, actAs));
|
|
380
|
+
return context.body(null, 204);
|
|
381
|
+
});
|
|
382
|
+
router.post(`${BASE}/incoming/:incomingId/rows`, describeRoute({
|
|
383
|
+
tags,
|
|
384
|
+
summary: 'Add a distribution row to an incoming document',
|
|
385
|
+
operationId: 'officeFlowsExampleCreateIncomingRow',
|
|
386
|
+
responses: {
|
|
387
|
+
201: dataResponse(Created, 'The row.'),
|
|
388
|
+
400: apiErrorResponse(400, 'No clerks or no department (`ROW_CLERKS_REQUIRED`, `DEPARTMENT_REQUIRED`, with `fieldViolations`).'),
|
|
389
|
+
401: unauthorized,
|
|
390
|
+
403: apiErrorResponse(403, 'Not the registrar, or not being dispatched (`ROWS_NOT_ALLOWED`).'),
|
|
391
|
+
404: notFound,
|
|
392
|
+
500: internal,
|
|
393
|
+
},
|
|
394
|
+
}), apiValidator('param', IncomingParams), apiValidator('query', ActAsQuery), apiValidator('json', RowInput), async (context) => {
|
|
395
|
+
const { incomingId } = context.req.valid('param');
|
|
396
|
+
const { actAs } = context.req.valid('query');
|
|
397
|
+
const row = context.req.valid('json');
|
|
398
|
+
const id = await service.addRow('incoming', incomingId, row, actAs);
|
|
399
|
+
return context.json({ data: { id: String(id) } }, 201);
|
|
400
|
+
});
|
|
401
|
+
router.post(`${BASE}/incoming/:incomingId/managementRows`, describeRoute({
|
|
402
|
+
tags,
|
|
403
|
+
summary: 'Copy an incoming document to a management group',
|
|
404
|
+
operationId: 'officeFlowsExampleCreateManagementRow',
|
|
405
|
+
description: 'A configured group by `groupId`, or a named group of chosen members.',
|
|
406
|
+
responses: {
|
|
407
|
+
201: dataResponse(Created, 'The row.'),
|
|
408
|
+
400: apiErrorResponse(400, 'No such configured group (`MANAGEMENT_GROUP_NOT_FOUND`), or no group name or no members (`MANAGEMENT_GROUP_REQUIRED`), with `fieldViolations`.'),
|
|
409
|
+
401: unauthorized,
|
|
410
|
+
403: apiErrorResponse(403, 'Not the registrar, or not being dispatched (`MANAGEMENT_NOT_ALLOWED`).'),
|
|
411
|
+
404: apiErrorResponse(404, 'No such document (`RECORD_NOT_FOUND`).'),
|
|
412
|
+
500: internal,
|
|
413
|
+
},
|
|
414
|
+
}), apiValidator('param', IncomingParams), apiValidator('query', ActAsQuery), apiValidator('json', ManagementRowInput), async (context) => {
|
|
415
|
+
const { incomingId } = context.req.valid('param');
|
|
416
|
+
const { actAs } = context.req.valid('query');
|
|
417
|
+
const { groupId, groupName, members } = context.req.valid('json');
|
|
418
|
+
const id = await service.addManagement(incomingId, {
|
|
419
|
+
...(groupId === undefined ? {} : { groupId: Number(groupId) }),
|
|
420
|
+
...(groupName === undefined ? {} : { groupName }),
|
|
421
|
+
...(members === undefined ? {} : { members }),
|
|
422
|
+
}, actAs);
|
|
423
|
+
return context.json({ data: { id: String(id) } }, 201);
|
|
424
|
+
});
|
|
425
|
+
router.delete(`${BASE}/managementRows/:rowId`, describeRoute({
|
|
426
|
+
tags,
|
|
427
|
+
summary: 'Remove a management copy that was not forwarded',
|
|
428
|
+
operationId: 'officeFlowsExampleDeleteManagementRow',
|
|
429
|
+
responses: {
|
|
430
|
+
204: noContent,
|
|
431
|
+
400: apiErrorResponse(400, 'Already forwarded (`MANAGEMENT_ROW_FORWARDED`).'),
|
|
432
|
+
401: unauthorized,
|
|
433
|
+
403: apiErrorResponse(403, 'Not the registrar (`MANAGEMENT_ROW_NOT_ALLOWED`).'),
|
|
434
|
+
404: notFound,
|
|
435
|
+
500: internal,
|
|
436
|
+
},
|
|
437
|
+
}), apiValidator('param', RowParams), apiValidator('query', ActAsQuery), async (context) => {
|
|
438
|
+
const { rowId } = context.req.valid('param');
|
|
439
|
+
const { actAs } = context.req.valid('query');
|
|
440
|
+
await service.removeManagement(rowId, actAs);
|
|
441
|
+
return context.body(null, 204);
|
|
442
|
+
});
|
|
443
|
+
router.delete(`${BASE}/rows/:rowId`, describeRoute({
|
|
444
|
+
tags,
|
|
445
|
+
summary: 'Remove a distribution row that was not dispatched',
|
|
446
|
+
operationId: 'officeFlowsExampleDeleteRow',
|
|
447
|
+
responses: {
|
|
448
|
+
204: noContent,
|
|
449
|
+
400: apiErrorResponse(400, 'Already dispatched (`ROW_DISPATCHED`).'),
|
|
450
|
+
401: unauthorized,
|
|
451
|
+
403: apiErrorResponse(403, 'Someone else added it (`ROW_OWNER_ONLY`).'),
|
|
452
|
+
404: notFound,
|
|
453
|
+
500: internal,
|
|
454
|
+
},
|
|
455
|
+
}), apiValidator('param', RowParams), apiValidator('query', ActAsQuery), async (context) => {
|
|
456
|
+
const { rowId } = context.req.valid('param');
|
|
457
|
+
const { actAs } = context.req.valid('query');
|
|
458
|
+
await service.removeRow(rowId, actAs);
|
|
459
|
+
return context.body(null, 204);
|
|
460
|
+
});
|
|
461
|
+
// ── Incoming-document tasks ─────────────────────────────────────────
|
|
462
|
+
router.get(`${BASE}/tasks`, describeRoute({
|
|
463
|
+
tags,
|
|
464
|
+
summary: 'List the persona’s tasks',
|
|
465
|
+
operationId: 'officeFlowsExampleListTasks',
|
|
466
|
+
description: 'Every kind of task assigned to the persona, each with its `kind`.',
|
|
467
|
+
responses: {
|
|
468
|
+
200: listResponse(OfficeRecord, PageMeta),
|
|
469
|
+
401: unauthorized,
|
|
470
|
+
500: internal,
|
|
471
|
+
},
|
|
472
|
+
}), apiValidator('query', ActAsPageQuery), async (context) => {
|
|
473
|
+
const query = context.req.valid('query');
|
|
474
|
+
return context.json(page(await service.myTasks(query.actAs, query), query));
|
|
475
|
+
});
|
|
476
|
+
router.get(`${BASE}/tasks/:taskKind/:taskId`, describeRoute({
|
|
477
|
+
tags,
|
|
478
|
+
summary: 'Get a task',
|
|
479
|
+
operationId: 'officeFlowsExampleGetTask',
|
|
480
|
+
responses: {
|
|
481
|
+
200: dataResponse(OfficeDetail),
|
|
482
|
+
401: unauthorized,
|
|
483
|
+
404: notFound,
|
|
484
|
+
500: internal,
|
|
485
|
+
},
|
|
486
|
+
}), apiValidator('param', TaskParams), apiValidator('query', ActAsQuery), async (context) => {
|
|
487
|
+
const { taskKind, taskId } = context.req.valid('param');
|
|
488
|
+
const { actAs } = context.req.valid('query');
|
|
489
|
+
return context.json(data(await service.taskDetail(taskKind, taskId, actAs)));
|
|
490
|
+
});
|
|
491
|
+
router.patch(`${BASE}/tasks/:taskKind/:taskId`, describeRoute({
|
|
492
|
+
tags,
|
|
493
|
+
summary: 'Edit a task in progress',
|
|
494
|
+
operationId: 'officeFlowsExampleUpdateTask',
|
|
495
|
+
responses: {
|
|
496
|
+
200: dataResponse(OfficeDetail, 'The task as edited.'),
|
|
497
|
+
...editRefusals,
|
|
498
|
+
401: unauthorized,
|
|
499
|
+
404: notFound,
|
|
500
|
+
500: internal,
|
|
501
|
+
},
|
|
502
|
+
}), apiValidator('param', TaskParams), apiValidator('query', ActAsQuery), apiValidator('json', TaskValuesInput), async (context) => {
|
|
503
|
+
const { taskKind, taskId } = context.req.valid('param');
|
|
504
|
+
const { actAs } = context.req.valid('query');
|
|
505
|
+
const { values } = context.req.valid('json');
|
|
506
|
+
await service.updateTask(taskKind, taskId, values, actAs);
|
|
507
|
+
return context.json(data(await service.taskDetail(taskKind, taskId, actAs)));
|
|
508
|
+
});
|
|
509
|
+
router.post(`${BASE}/tasks/:taskKind/:taskId/fire`, describeRoute({
|
|
510
|
+
tags,
|
|
511
|
+
summary: 'Fire a transition on a task',
|
|
512
|
+
operationId: 'officeFlowsExampleFireTaskTransition',
|
|
513
|
+
responses: {
|
|
514
|
+
204: noContent,
|
|
515
|
+
...fireRefusals,
|
|
516
|
+
401: unauthorized,
|
|
517
|
+
404: notFound,
|
|
518
|
+
500: internal,
|
|
519
|
+
},
|
|
520
|
+
}), apiValidator('param', TaskParams), apiValidator('query', ActAsQuery), apiValidator('json', FireInput), async (context) => {
|
|
521
|
+
const { taskKind, taskId } = context.req.valid('param');
|
|
522
|
+
const { actAs } = context.req.valid('query');
|
|
523
|
+
const { transition, input } = context.req.valid('json');
|
|
524
|
+
await fire(() => service.fireTask(taskKind, taskId, transition, input, actAs));
|
|
525
|
+
return context.body(null, 204);
|
|
526
|
+
});
|
|
527
|
+
router.post(`${BASE}/tasks/:taskKind/:taskId/rows`, describeRoute({
|
|
528
|
+
tags,
|
|
529
|
+
summary: 'Add a distribution row to a task',
|
|
530
|
+
operationId: 'officeFlowsExampleCreateTaskRow',
|
|
531
|
+
description: 'A clerk’s or a team’s task dispatches further; an executor’s has nothing to dispatch.',
|
|
532
|
+
responses: {
|
|
533
|
+
201: dataResponse(Created, 'The row.'),
|
|
534
|
+
400: apiErrorResponse(400, 'No clerks or no department (`ROW_CLERKS_REQUIRED`, `DEPARTMENT_REQUIRED`, with `fieldViolations`).'),
|
|
535
|
+
401: unauthorized,
|
|
536
|
+
403: apiErrorResponse(403, 'Not an assignee of a task in progress (`TASK_ROWS_NOT_ALLOWED`).'),
|
|
537
|
+
404: notFound,
|
|
538
|
+
500: internal,
|
|
539
|
+
},
|
|
540
|
+
}), apiValidator('param', DispatchingTaskParams), apiValidator('query', ActAsQuery), apiValidator('json', RowInput), async (context) => {
|
|
541
|
+
const { taskKind, taskId } = context.req.valid('param');
|
|
542
|
+
const { actAs } = context.req.valid('query');
|
|
543
|
+
const row = context.req.valid('json');
|
|
544
|
+
const id = await service.addRow(taskKind, taskId, row, actAs);
|
|
545
|
+
return context.json({ data: { id: String(id) } }, 201);
|
|
546
|
+
});
|
|
547
|
+
return new Hono().route('/', router);
|
|
548
|
+
});
|
|
549
|
+
const routes = [
|
|
550
|
+
apiRoutes,
|
|
551
|
+
];
|
|
552
|
+
export default routes;
|
|
553
|
+
//# sourceMappingURL=index.js.map
|