@gadmin2n/schematics 0.0.150 → 0.0.151

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.
Files changed (81) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.md +125 -36
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +42 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/gitignore +2 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/server/.seed-timestamp +0 -0
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +2 -0
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/check-dev-env.js +218 -0
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/page-manage.ts +78 -12
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +37 -67
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +0 -17
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agenda/agenda.controller.ts +46 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.ts +60 -1
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-callback.controller.ts +3 -0
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.controller.ts +9 -1
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.ts +55 -0
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.module.ts +2 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/page-transfer.service.ts +491 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.dto.ts +213 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.module.ts +28 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/resource-transfer.service.ts +137 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/role-transfer.service.ts +248 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/transfer-token.service.ts +65 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/user-transfer.service.ts +146 -0
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.ts +55 -0
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.module.ts +2 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.ts +55 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.module.ts +2 -0
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.spec.ts +46 -0
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.ts +3 -2
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +55 -0
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.module.ts +2 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +1 -0
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +96 -14
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +41 -41
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.spec.ts +36 -0
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.ts +90 -0
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-catalog.spec.ts +4 -0
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-trigger.pg.spec.ts +1 -0
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution-idempotency.spec.ts +115 -63
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.spec.ts +166 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.ts +217 -0
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.spec.ts +33 -0
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.ts +57 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.spec.ts +196 -0
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.ts +125 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-node-type.controller.ts +9 -3
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +148 -4
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +12 -1
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +14 -0
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +75 -45
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +25 -0
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferExportModal.tsx +115 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferImportModal.tsx +257 -0
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +0 -2
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +40 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +15 -13
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +40 -0
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +15 -13
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +2 -1
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +89 -65
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/list.tsx +51 -127
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/permissionReadme/index.tsx +53 -109
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +45 -41
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/list.tsx +51 -72
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/list.tsx +49 -40
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +16 -5
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.test.tsx +28 -10
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.test.tsx +60 -1
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +94 -12
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-instance-show.css +13 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +3 -3
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +8 -1
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +167 -94
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +95 -95
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.test.tsx +81 -0
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.tsx +126 -0
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +48 -52
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.ts +2 -2
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +1 -3
  79. package/package.json +1 -1
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/ac.config.ts +0 -24
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/SqlModal.tsx +0 -495
@@ -297,6 +297,25 @@ const NODE_DEFINITIONS: BaseNodeTypeSeed[] = [
297
297
  default: 20,
298
298
  description: '顺序调度器最多同时处理的业务对象数量',
299
299
  },
300
+ failureCallback: {
301
+ type: 'object',
302
+ description: 'Workflow 最终失败后通知业务系统',
303
+ properties: {
304
+ connectionRef: {
305
+ type: 'string',
306
+ minLength: 1,
307
+ description: '业务系统连接编码',
308
+ },
309
+ path: {
310
+ type: 'string',
311
+ minLength: 1,
312
+ pattern: '^/',
313
+ description: '业务失败处理 API 的相对路径',
314
+ },
315
+ },
316
+ required: ['connectionRef', 'path'],
317
+ additionalProperties: false,
318
+ },
300
319
  },
301
320
  required: ['registrationCode', 'operationRules', 'processingMode'],
302
321
  allOf: [
@@ -433,25 +452,26 @@ const NODE_DEFINITIONS: BaseNodeTypeSeed[] = [
433
452
  {
434
453
  type: 'db_execute',
435
454
  category: 'ACTION',
436
- label: '数据库操作',
455
+ label: '数据库 Function',
437
456
  icon: 'ConsoleSqlOutlined',
438
- description: '使用 SQL 查询或修改当前服务注册的数据库',
457
+ description: '调用当前 GAdmin 数据库 workflow_api 中的 Function',
439
458
  configSchema: {
440
459
  type: 'object',
441
460
  properties: {
442
- allowWrite: {
443
- type: 'boolean',
444
- description: '是否允许新增、更新或删除数据',
445
- },
446
- sql: {
447
- type: 'string',
448
- minLength: 1,
449
- description: '要执行的单条 SQL',
461
+ functionRef: {
462
+ type: 'object',
463
+ properties: {
464
+ schema: { type: 'string', enum: ['workflow_api'] },
465
+ name: { type: 'string', minLength: 1 },
466
+ identityArguments: { type: 'string' },
467
+ },
468
+ required: ['schema', 'name', 'identityArguments'],
469
+ additionalProperties: false,
450
470
  },
451
- parameters: {
471
+ argumentBindings: {
452
472
  type: 'array',
453
473
  items: PARAMETER_BINDING_SCHEMA,
454
- description: 'SQL 中参数占位符对应的值',
474
+ description: '按 Function 参数顺序提供的值',
455
475
  },
456
476
  timeoutSeconds: {
457
477
  type: 'integer',
@@ -460,17 +480,14 @@ const NODE_DEFINITIONS: BaseNodeTypeSeed[] = [
460
480
  description: '执行超时时间(秒)',
461
481
  },
462
482
  },
463
- required: ['allowWrite', 'sql'],
483
+ required: ['functionRef', 'argumentBindings'],
464
484
  additionalProperties: false,
465
485
  },
466
486
  inputSchema: { description: '上一个节点的完整结果' },
467
487
  outputSchema: {
468
488
  type: 'object',
469
489
  properties: {
470
- rows: { type: 'array' },
471
- rowCount: { type: 'number' },
472
- affectedRows: { type: 'number' },
473
- insertedId: { type: 'string' },
490
+ result: { description: 'Function 返回值' },
474
491
  },
475
492
  },
476
493
  outputs: [],
@@ -794,58 +811,12 @@ const NODE_DEFINITIONS: BaseNodeTypeSeed[] = [
794
811
  ];
795
812
 
796
813
  // ─── APPROVAL ──────────────────────────────────────────────────────────────
797
- const approvalDefinition: BaseNodeTypeSeed = {
814
+ const approvalDefinition: Omit<BaseNodeTypeSeed, 'configSchema' | 'outputs'> = {
798
815
  type: 'approval',
799
816
  category: 'APPROVAL',
800
817
  label: '人工审批',
801
818
  icon: 'CheckCircleOutlined',
802
819
  description: '创建审批请求并等待审批人通过、拒绝或超时',
803
- configSchema: {
804
- type: 'object',
805
- properties: {
806
- approvers: {
807
- type: 'array',
808
- items: {
809
- type: 'object',
810
- properties: {
811
- type: { type: 'string', enum: ['user', 'group'] },
812
- id: { type: 'string' },
813
- },
814
- required: ['type', 'id'],
815
- },
816
- description: '可以处理本次审批的用户或可复用用户组',
817
- },
818
- approvalMode: {
819
- type: 'string',
820
- enum: ['any', 'all', 'percentage'],
821
- description: '任意一人、全部通过或达到指定比例',
822
- },
823
- minApprovalCount: {
824
- type: 'number',
825
- description: '达到通过条件所需的最少人数',
826
- },
827
- timeout: { type: 'number', description: '审批超时时间(秒)' },
828
- timeoutAction: {
829
- type: 'string',
830
- enum: ['auto_approve', 'auto_reject', 'escalate'],
831
- description: '审批超时后的处理动作',
832
- },
833
- escalateTo: {
834
- type: 'array',
835
- items: { type: 'string' },
836
- description: '审批超时后的升级处理人',
837
- },
838
- reminderInterval: {
839
- type: 'number',
840
- description: '提醒间隔(小时),0 表示不提醒',
841
- },
842
- allowDelegate: {
843
- type: 'boolean',
844
- description: '是否允许审批人转交给其他人',
845
- },
846
- },
847
- required: ['approvers'],
848
- },
849
820
  inputSchema: { description: '上一个节点的完整结果' },
850
821
  outputSchema: {
851
822
  type: 'object',
@@ -869,7 +840,6 @@ const approvalDefinition: BaseNodeTypeSeed = {
869
840
  },
870
841
  required: ['previous', 'result'],
871
842
  },
872
- outputs: [],
873
843
  };
874
844
 
875
845
  // ─── SUB WORKFLOW ──────────────────────────────────────────────────────────
@@ -1344,9 +1314,9 @@ const dedicatedEditorNodes: NodeTypeSeed[] = [
1344
1314
  ),
1345
1315
  schemaVersion:
1346
1316
  type === 'event_trigger'
1347
- ? 5
1317
+ ? 6
1348
1318
  : type === 'db_execute'
1349
- ? 4
1319
+ ? 5
1350
1320
  : type === 'parallel'
1351
1321
  ? 6
1352
1322
  : ['if_else', 'switch'].includes(type)
@@ -8,23 +8,6 @@ const config: Record<string, any> = {
8
8
  logger: {
9
9
  level: 'debug',
10
10
  },
11
- roles: {
12
- codytang: ['GUEST'],
13
-
14
- v_bmzmzhao: ['SYSTEM_ADMIN'],
15
- miamgao: ['SYSTEM_ADMIN'],
16
- benzemazhu: ['PRODUCT'],
17
- asherzhou: ['PRODUCT'],
18
- ivyyfchen: ['PRODUCT'],
19
- haonanli: ['PRODUCT'],
20
- libearxiong: ['PRODUCT'],
21
- jasonzxyin: ['PRODUCT'],
22
- masonqliu: ['PRODUCT'],
23
-
24
- admin: ['SYSTEM_ADMIN'],
25
- kavenma: ['SYSTEM_ADMIN'],
26
- clzhu: ['SYSTEM_ADMIN'],
27
- },
28
11
  prisma: {
29
12
  log: ['info', 'query', 'warn', 'error'],
30
13
  DATABASE_URL: process.env.TASK_DATABASE_URL,
@@ -10,6 +10,7 @@ import {
10
10
  UseGuards,
11
11
  } from '@nestjs/common';
12
12
  import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
13
+ import { UseRoles } from 'nest-access-control';
13
14
  import { AgendaService } from './agenda.service';
14
15
 
15
16
  class JobIdsDto {
@@ -43,12 +44,22 @@ export class AgendaController {
43
44
  constructor(private readonly agendaService: AgendaService) {}
44
45
 
45
46
  @Get('overview')
47
+ @UseRoles({
48
+ resource: 'agenda',
49
+ action: 'read',
50
+ possession: 'any',
51
+ })
46
52
  @ApiOkResponse({ description: 'Get execution metrics overview (24h/total)' })
47
53
  async getOverview() {
48
54
  return this.agendaService.getMetricsOverview();
49
55
  }
50
56
 
51
57
  @Get('jobs')
58
+ @UseRoles({
59
+ resource: 'agenda',
60
+ action: 'read',
61
+ possession: 'any',
62
+ })
52
63
  @ApiOkResponse({ description: 'List jobs with overview stats' })
53
64
  async getJobs(@Query() query: JobsQueryDto) {
54
65
  return this.agendaService.getJobs({
@@ -65,36 +76,66 @@ export class AgendaController {
65
76
  }
66
77
 
67
78
  @Post('requeue')
79
+ @UseRoles({
80
+ resource: 'agenda',
81
+ action: 'update',
82
+ possession: 'any',
83
+ })
68
84
  @ApiOkResponse({ description: 'Requeue jobs by IDs' })
69
85
  async requeue(@Body() body: JobIdsDto) {
70
86
  return this.agendaService.requeueByIds(body.jobIds);
71
87
  }
72
88
 
73
89
  @Post('retry')
90
+ @UseRoles({
91
+ resource: 'agenda',
92
+ action: 'update',
93
+ possession: 'any',
94
+ })
74
95
  @ApiOkResponse({ description: 'Retry failed jobs by IDs' })
75
96
  async retry(@Body() body: JobIdsDto) {
76
97
  return this.agendaService.retryByIds(body.jobIds);
77
98
  }
78
99
 
79
100
  @Post('delete')
101
+ @UseRoles({
102
+ resource: 'agenda',
103
+ action: 'delete',
104
+ possession: 'any',
105
+ })
80
106
  @ApiOkResponse({ description: 'Delete jobs by IDs' })
81
107
  async delete(@Body() body: JobIdsDto) {
82
108
  return this.agendaService.deleteByIds(body.jobIds);
83
109
  }
84
110
 
85
111
  @Post('disable')
112
+ @UseRoles({
113
+ resource: 'agenda',
114
+ action: 'update',
115
+ possession: 'any',
116
+ })
86
117
  @ApiOkResponse({ description: 'Disable (pause) jobs by IDs' })
87
118
  async disable(@Body() body: JobIdsDto) {
88
119
  return this.agendaService.disableByIds(body.jobIds);
89
120
  }
90
121
 
91
122
  @Post('enable')
123
+ @UseRoles({
124
+ resource: 'agenda',
125
+ action: 'update',
126
+ possession: 'any',
127
+ })
92
128
  @ApiOkResponse({ description: 'Enable (resume) jobs by IDs' })
93
129
  async enable(@Body() body: JobIdsDto) {
94
130
  return this.agendaService.enableByIds(body.jobIds);
95
131
  }
96
132
 
97
133
  @Get('job/:jobName')
134
+ @UseRoles({
135
+ resource: 'agenda',
136
+ action: 'read',
137
+ possession: 'any',
138
+ })
98
139
  @ApiOkResponse({ description: 'Get single job detail with run statistics' })
99
140
  async getJobDetail(@Param('jobName') jobName: string) {
100
141
  const detail = await this.agendaService.getJobDetail(jobName);
@@ -103,6 +144,11 @@ export class AgendaController {
103
144
  }
104
145
 
105
146
  @Get('logs')
147
+ @UseRoles({
148
+ resource: 'agenda',
149
+ action: 'read',
150
+ possession: 'any',
151
+ })
106
152
  @ApiOkResponse({ description: 'Get execution history logs for a job' })
107
153
  async getLogs(@Query() query: JobLogsQueryDto) {
108
154
  return this.agendaService.getJobLogs({
@@ -1,3 +1,4 @@
1
+ import { ACGuard } from '@gadmin2n/nest-common';
1
2
  import {
2
3
  Body,
3
4
  Controller,
@@ -11,8 +12,10 @@ import {
11
12
  Query,
12
13
  Req,
13
14
  UnauthorizedException,
15
+ UseGuards,
14
16
  } from '@nestjs/common';
15
17
  import { ApiTags } from '@nestjs/swagger';
18
+ import { UseRoles } from 'nest-access-control';
16
19
  import { PrismaService } from 'nestjs-prisma';
17
20
  import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
18
21
  import { ImportPayloadDto } from './canvas-export.dto';
@@ -25,8 +28,9 @@ import {
25
28
  } from './canvas.dto';
26
29
  import { CanvasService } from './canvas.service';
27
30
 
28
- @ApiTags('canvas')
31
+ @UseGuards(ACGuard)
29
32
  @Controller('canvas')
33
+ @ApiTags('canvas')
30
34
  export class CanvasController {
31
35
  constructor(
32
36
  private readonly canvasService: CanvasService,
@@ -35,11 +39,21 @@ export class CanvasController {
35
39
  ) {}
36
40
 
37
41
  @Get()
42
+ @UseRoles({
43
+ resource: 'canvas',
44
+ action: 'read',
45
+ possession: 'any',
46
+ })
38
47
  findAll(@Req() req) {
39
48
  return this.canvasService.findAllByUser(req.user.userid);
40
49
  }
41
50
 
42
51
  @Get('all')
52
+ @UseRoles({
53
+ resource: 'canvas',
54
+ action: 'read',
55
+ possession: 'any',
56
+ })
43
57
  async findAllForAdmin(@Req() req) {
44
58
  const record = await this.prisma.user.findFirst({
45
59
  where: { userid: req.user.userid },
@@ -53,6 +67,11 @@ export class CanvasController {
53
67
  }
54
68
 
55
69
  @Post()
70
+ @UseRoles({
71
+ resource: 'canvas',
72
+ action: 'create',
73
+ possession: 'any',
74
+ })
56
75
  create(@Req() req, @Body() dto: CreateCanvasDto) {
57
76
  return this.canvasService.create(req.user.userid, dto);
58
77
  }
@@ -76,6 +95,11 @@ export class CanvasController {
76
95
  }
77
96
 
78
97
  @Get(':id')
98
+ @UseRoles({
99
+ resource: 'canvas',
100
+ action: 'read',
101
+ possession: 'any',
102
+ })
79
103
  findOne(@Req() req, @Param('id') id: string) {
80
104
  const roles: string[] = req.user?.configPerms?.roles ?? [];
81
105
  const isAdmin = roles.includes('SYSTEM_ADMIN');
@@ -86,6 +110,11 @@ export class CanvasController {
86
110
  }
87
111
 
88
112
  @Put(':id')
113
+ @UseRoles({
114
+ resource: 'canvas',
115
+ action: 'update',
116
+ possession: 'any',
117
+ })
89
118
  update(@Req() req, @Param('id') id: string, @Body() dto: UpdateCanvasDto) {
90
119
  const roles: string[] = req.user?.configPerms?.roles ?? [];
91
120
  const isAdmin = roles.includes('SYSTEM_ADMIN');
@@ -97,6 +126,11 @@ export class CanvasController {
97
126
  }
98
127
 
99
128
  @Delete(':id')
129
+ @UseRoles({
130
+ resource: 'canvas',
131
+ action: 'delete',
132
+ possession: 'any',
133
+ })
100
134
  remove(@Req() req, @Param('id') id: string) {
101
135
  return this.canvasService.remove(id, req.user.userid);
102
136
  }
@@ -104,6 +138,11 @@ export class CanvasController {
104
138
  // ─── Export/Import Endpoints ──────────────────────────────────────────────────
105
139
 
106
140
  @Post(':id/export-token')
141
+ @UseRoles({
142
+ resource: 'canvas',
143
+ action: 'read',
144
+ possession: 'any',
145
+ })
107
146
  async generateExportToken(@Param('id') id: string, @Req() req) {
108
147
  const baseUrl = `${req.protocol}://${req.get('host')}/api`;
109
148
  return this.canvasExportService.generateExportToken(id, baseUrl);
@@ -122,21 +161,41 @@ export class CanvasController {
122
161
  }
123
162
 
124
163
  @Post('import-preview')
164
+ @UseRoles({
165
+ resource: 'canvas',
166
+ action: 'update',
167
+ possession: 'any',
168
+ })
125
169
  async importPreview(@Body() dto: ImportPayloadDto) {
126
170
  return this.canvasExportService.importPreview(dto.payload);
127
171
  }
128
172
 
129
173
  @Post('import-confirm')
174
+ @UseRoles({
175
+ resource: 'canvas',
176
+ action: 'update',
177
+ possession: 'any',
178
+ })
130
179
  async importConfirm(@Body() dto: ImportPayloadDto, @Req() req) {
131
180
  return this.canvasExportService.importConfirm(dto.payload, req.user.userid);
132
181
  }
133
182
 
134
183
  @Post(':id/publish')
184
+ @UseRoles({
185
+ resource: 'canvas',
186
+ action: 'update',
187
+ possession: 'any',
188
+ })
135
189
  publish(@Req() req, @Param('id') id: string, @Body() dto: PublishCanvasDto) {
136
190
  return this.canvasService.publish(id, req.user.userid, dto);
137
191
  }
138
192
 
139
193
  @Delete(':id/unpublish')
194
+ @UseRoles({
195
+ resource: 'canvas',
196
+ action: 'update',
197
+ possession: 'any',
198
+ })
140
199
  unpublish(@Req() req, @Param('id') id: string) {
141
200
  return this.canvasService.unpublish(id, req.user.userid);
142
201
  }
@@ -1,15 +1,18 @@
1
+ import { ACGuard } from '@gadmin2n/nest-common';
1
2
  import {
2
3
  BadRequestException,
3
4
  Body,
4
5
  Controller,
5
6
  Headers,
6
7
  Post,
8
+ UseGuards,
7
9
  } from '@nestjs/common';
8
10
  import { createHash } from 'node:crypto';
9
11
  import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
10
12
  import { WorkflowRuntimeConfigService } from '../workflowRuntimeConfig/workflow-runtime-config.service';
11
13
  import { ExternalInteractionService } from './external-interaction.service';
12
14
 
15
+ @UseGuards(ACGuard)
13
16
  @Controller('workflow/external-callback')
14
17
  export class ExternalCallbackController {
15
18
  constructor(
@@ -1,11 +1,19 @@
1
- import { Controller, Get, Query } from '@nestjs/common';
1
+ import { ACGuard } from '@gadmin2n/nest-common';
2
+ import { Controller, Get, Query, UseGuards } from '@nestjs/common';
3
+ import { UseRoles } from 'nest-access-control';
2
4
  import { WorkflowCallbackUrlService } from './workflow-callback-url.service';
3
5
 
6
+ @UseGuards(ACGuard)
4
7
  @Controller('workflow-webhook')
5
8
  export class WorkflowCallbackUrlController {
6
9
  constructor(private readonly callbackUrls: WorkflowCallbackUrlService) {}
7
10
 
8
11
  @Get('endpoint')
12
+ @UseRoles({
13
+ resource: 'workflow',
14
+ action: 'read',
15
+ possession: 'any',
16
+ })
9
17
  async resolveEndpoint(@Query('path') path = '') {
10
18
  return { endpoint: await this.callbackUrls.resolvePath(path) };
11
19
  }
@@ -13,13 +13,16 @@ import {
13
13
  Body,
14
14
  Controller,
15
15
  Delete,
16
+ Get,
16
17
  Inject,
17
18
  NotFoundException,
18
19
  Param,
19
20
  ParseIntPipe,
20
21
  Patch,
21
22
  Post,
23
+ Query,
22
24
  Req,
25
+ UnauthorizedException,
23
26
  UploadedFile,
24
27
  UseGuards,
25
28
  UseInterceptors,
@@ -43,6 +46,9 @@ import {
43
46
  } from '../../generated/page/dto/page-types.dto';
44
47
  import { UpdatePageDto } from '../../generated/page/dto/update-page.dto';
45
48
  import { PageEntity } from '../../generated/page/entities/page.entity';
49
+ import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
50
+ import { PageTransferService } from '../permTransfer/page-transfer.service';
51
+ import { ImportPayloadDto } from '../permTransfer/perm-transfer.dto';
46
52
  import { PageService } from './page.service';
47
53
 
48
54
  import { ConfigService } from '@nestjs/config';
@@ -81,6 +87,7 @@ export class CreatePageWithResourcesDto extends CreatePageDto {
81
87
  export class PageController {
82
88
  constructor(
83
89
  private readonly pageService: PageService,
90
+ private readonly pageTransferService: PageTransferService,
84
91
  private readonly config: ConfigService,
85
92
  @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
86
93
  ) {}
@@ -227,6 +234,54 @@ export class PageController {
227
234
  return res;
228
235
  }
229
236
 
237
+ // ─── Export/Import (cross-environment transfer) ────────────────────────────
238
+
239
+ @Post(':code/export-token')
240
+ @UseRoles({
241
+ resource: 'page',
242
+ action: 'read',
243
+ possession: 'any',
244
+ })
245
+ async generateExportToken(@Param('code') code: string, @Req() req) {
246
+ const baseUrl = `${req.protocol}://${req.get('host')}/api`;
247
+ return this.pageTransferService.generateExportToken(code, baseUrl);
248
+ }
249
+
250
+ @Get('export/:code')
251
+ @AllowUnauthorizedRequest()
252
+ async getExportPayload(
253
+ @Param('code') code: string,
254
+ @Query('token') token: string,
255
+ ) {
256
+ if (!token) {
257
+ throw new UnauthorizedException('Export token is required');
258
+ }
259
+ return this.pageTransferService.getExportPayload(code, token);
260
+ }
261
+
262
+ @Post('import-preview')
263
+ @UseRoles({
264
+ resource: 'page',
265
+ action: 'update',
266
+ possession: 'any',
267
+ })
268
+ async importPreview(@Body() dto: ImportPayloadDto) {
269
+ return this.pageTransferService.importPreview(dto.payload);
270
+ }
271
+
272
+ @Post('import-confirm')
273
+ @UseRoles({
274
+ resource: 'page',
275
+ action: 'update',
276
+ possession: 'any',
277
+ })
278
+ async importConfirm(@Body() dto: ImportPayloadDto, @Req() req) {
279
+ return this.pageTransferService.importConfirm(
280
+ dto.payload,
281
+ req.user.username ?? req.user.userid,
282
+ );
283
+ }
284
+
230
285
  @Post('upload')
231
286
  @UseRoles({
232
287
  resource: 'page',
@@ -1,8 +1,10 @@
1
1
  import { Module } from '@nestjs/common';
2
+ import { PermTransferModule } from '../permTransfer/perm-transfer.module';
2
3
  import { PageController } from './page.controller';
3
4
  import { PageService } from './page.service';
4
5
 
5
6
  @Module({
7
+ imports: [PermTransferModule],
6
8
  controllers: [PageController],
7
9
  providers: [PageService],
8
10
  exports: [PageService],