@gadmin2n/schematics 0.0.150 → 0.0.152
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/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.md +125 -36
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +42 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/gitignore +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/.seed-timestamp +0 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/check-dev-env.js +218 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/page-manage.ts +78 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +37 -67
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +0 -17
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agenda/agenda.controller.ts +46 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.ts +60 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-callback.controller.ts +3 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.controller.ts +9 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/page-transfer.service.ts +491 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.dto.ts +213 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/perm-transfer.module.ts +28 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/resource-transfer.service.ts +137 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/role-transfer.service.ts +248 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/transfer-token.service.ts +65 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/permTransfer/user-transfer.service.ts +146 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.spec.ts +46 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.ts +3 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.ts +55 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.module.ts +2 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +96 -14
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +41 -41
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.spec.ts +36 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-database-function.ts +90 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-catalog.spec.ts +4 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-trigger.pg.spec.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution-idempotency.spec.ts +115 -63
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.spec.ts +166 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-outbox.service.ts +217 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.spec.ts +33 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle-runtime.controller.ts +57 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.spec.ts +196 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-lifecycle.service.ts +125 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-node-type.controller.ts +9 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +148 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +12 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +14 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +75 -45
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +25 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferExportModal.tsx +115 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/TransferImportModal.tsx +257 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +0 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +40 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +15 -13
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +40 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +15 -13
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +2 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +89 -65
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/list.tsx +51 -127
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/permissionReadme/index.tsx +53 -109
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +45 -41
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/list.tsx +51 -72
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/list.tsx +49 -40
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +16 -5
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.test.tsx +28 -10
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.test.tsx +60 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +94 -12
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-instance-show.css +13 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +3 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +8 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +167 -94
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +95 -95
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.test.tsx +81 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerLifecycleConfigEditor.tsx +126 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +48 -52
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.ts +2 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +1 -3
- package/package.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/CODEBUDDY.local.md +0 -8
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/ac.config.ts +0 -24
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/SqlModal.tsx +0 -495
|
@@ -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/resource/dto/resource-types.dto';
|
|
44
47
|
import { UpdateResourceDto } from '../../generated/resource/dto/update-resource.dto';
|
|
45
48
|
import { ResourceEntity } from '../../generated/resource/entities/resource.entity';
|
|
49
|
+
import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
|
|
50
|
+
import { ImportPayloadDto } from '../permTransfer/perm-transfer.dto';
|
|
51
|
+
import { ResourceTransferService } from '../permTransfer/resource-transfer.service';
|
|
46
52
|
import { ResourceService } from './resource.service';
|
|
47
53
|
|
|
48
54
|
import { ConfigService } from '@nestjs/config';
|
|
@@ -54,6 +60,7 @@ import { FileInterceptor } from '@nestjs/platform-express';
|
|
|
54
60
|
export class ResourceController {
|
|
55
61
|
constructor(
|
|
56
62
|
private readonly resourceService: ResourceService,
|
|
63
|
+
private readonly resourceTransferService: ResourceTransferService,
|
|
57
64
|
private readonly config: ConfigService,
|
|
58
65
|
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
|
|
59
66
|
) {}
|
|
@@ -173,6 +180,54 @@ export class ResourceController {
|
|
|
173
180
|
return res;
|
|
174
181
|
}
|
|
175
182
|
|
|
183
|
+
// ─── Export/Import (cross-environment transfer) ────────────────────────────
|
|
184
|
+
|
|
185
|
+
@Post(':code/export-token')
|
|
186
|
+
@UseRoles({
|
|
187
|
+
resource: 'resource',
|
|
188
|
+
action: 'read',
|
|
189
|
+
possession: 'any',
|
|
190
|
+
})
|
|
191
|
+
async generateExportToken(@Param('code') code: string, @Req() req) {
|
|
192
|
+
const baseUrl = `${req.protocol}://${req.get('host')}/api`;
|
|
193
|
+
return this.resourceTransferService.generateExportToken(code, baseUrl);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@Get('export/:code')
|
|
197
|
+
@AllowUnauthorizedRequest()
|
|
198
|
+
async getExportPayload(
|
|
199
|
+
@Param('code') code: string,
|
|
200
|
+
@Query('token') token: string,
|
|
201
|
+
) {
|
|
202
|
+
if (!token) {
|
|
203
|
+
throw new UnauthorizedException('Export token is required');
|
|
204
|
+
}
|
|
205
|
+
return this.resourceTransferService.getExportPayload(code, token);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@Post('import-preview')
|
|
209
|
+
@UseRoles({
|
|
210
|
+
resource: 'resource',
|
|
211
|
+
action: 'update',
|
|
212
|
+
possession: 'any',
|
|
213
|
+
})
|
|
214
|
+
async importPreview(@Body() dto: ImportPayloadDto) {
|
|
215
|
+
return this.resourceTransferService.importPreview(dto.payload);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@Post('import-confirm')
|
|
219
|
+
@UseRoles({
|
|
220
|
+
resource: 'resource',
|
|
221
|
+
action: 'update',
|
|
222
|
+
possession: 'any',
|
|
223
|
+
})
|
|
224
|
+
async importConfirm(@Body() dto: ImportPayloadDto, @Req() req) {
|
|
225
|
+
return this.resourceTransferService.importConfirm(
|
|
226
|
+
dto.payload,
|
|
227
|
+
req.user.username ?? req.user.userid,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
176
231
|
@Post('upload')
|
|
177
232
|
@UseRoles({
|
|
178
233
|
resource: 'resource',
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Module } from '@nestjs/common';
|
|
2
|
+
import { PermTransferModule } from '../permTransfer/perm-transfer.module';
|
|
2
3
|
import { ResourceController } from './resource.controller';
|
|
3
4
|
import { ResourceService } from './resource.service';
|
|
4
5
|
|
|
5
6
|
@Module({
|
|
7
|
+
imports: [PermTransferModule],
|
|
6
8
|
controllers: [ResourceController],
|
|
7
9
|
providers: [ResourceService],
|
|
8
10
|
exports: [ResourceService],
|
|
@@ -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/role/dto/role-types.dto';
|
|
44
47
|
import { UpdateRoleDto } from '../../generated/role/dto/update-role.dto';
|
|
45
48
|
import { RoleEntity } from '../../generated/role/entities/role.entity';
|
|
49
|
+
import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
|
|
50
|
+
import { ImportPayloadDto } from '../permTransfer/perm-transfer.dto';
|
|
51
|
+
import { RoleTransferService } from '../permTransfer/role-transfer.service';
|
|
46
52
|
import { RoleService } from './role.service';
|
|
47
53
|
|
|
48
54
|
import { ConfigService } from '@nestjs/config';
|
|
@@ -71,6 +77,7 @@ export class CreateRoleWithPagesDto extends CreateRoleDto {
|
|
|
71
77
|
export class RoleController {
|
|
72
78
|
constructor(
|
|
73
79
|
private readonly roleService: RoleService,
|
|
80
|
+
private readonly roleTransferService: RoleTransferService,
|
|
74
81
|
private readonly config: ConfigService,
|
|
75
82
|
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
|
|
76
83
|
) {}
|
|
@@ -187,6 +194,54 @@ export class RoleController {
|
|
|
187
194
|
return res;
|
|
188
195
|
}
|
|
189
196
|
|
|
197
|
+
// ─── Export/Import (cross-environment transfer) ────────────────────────────
|
|
198
|
+
|
|
199
|
+
@Post(':name/export-token')
|
|
200
|
+
@UseRoles({
|
|
201
|
+
resource: 'role',
|
|
202
|
+
action: 'read',
|
|
203
|
+
possession: 'any',
|
|
204
|
+
})
|
|
205
|
+
async generateExportToken(@Param('name') name: string, @Req() req) {
|
|
206
|
+
const baseUrl = `${req.protocol}://${req.get('host')}/api`;
|
|
207
|
+
return this.roleTransferService.generateExportToken(name, baseUrl);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@Get('export/:name')
|
|
211
|
+
@AllowUnauthorizedRequest()
|
|
212
|
+
async getExportPayload(
|
|
213
|
+
@Param('name') name: string,
|
|
214
|
+
@Query('token') token: string,
|
|
215
|
+
) {
|
|
216
|
+
if (!token) {
|
|
217
|
+
throw new UnauthorizedException('Export token is required');
|
|
218
|
+
}
|
|
219
|
+
return this.roleTransferService.getExportPayload(name, token);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@Post('import-preview')
|
|
223
|
+
@UseRoles({
|
|
224
|
+
resource: 'role',
|
|
225
|
+
action: 'update',
|
|
226
|
+
possession: 'any',
|
|
227
|
+
})
|
|
228
|
+
async importPreview(@Body() dto: ImportPayloadDto) {
|
|
229
|
+
return this.roleTransferService.importPreview(dto.payload);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@Post('import-confirm')
|
|
233
|
+
@UseRoles({
|
|
234
|
+
resource: 'role',
|
|
235
|
+
action: 'update',
|
|
236
|
+
possession: 'any',
|
|
237
|
+
})
|
|
238
|
+
async importConfirm(@Body() dto: ImportPayloadDto, @Req() req) {
|
|
239
|
+
return this.roleTransferService.importConfirm(
|
|
240
|
+
dto.payload,
|
|
241
|
+
req.user.username ?? req.user.userid,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
190
245
|
@Post('upload')
|
|
191
246
|
@UseRoles({
|
|
192
247
|
resource: 'role',
|
package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.module.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Module } from '@nestjs/common';
|
|
2
2
|
import { PrismaService } from 'nestjs-prisma';
|
|
3
|
+
import { PermTransferModule } from '../permTransfer/perm-transfer.module';
|
|
3
4
|
import { RoleController } from './role.controller';
|
|
4
5
|
import { RoleService } from './role.service';
|
|
5
6
|
import { RolesRefresherService } from './roles-refresher.service';
|
|
6
7
|
|
|
7
8
|
@Module({
|
|
9
|
+
imports: [PermTransferModule],
|
|
8
10
|
providers: [RoleService, RolesRefresherService, PrismaService],
|
|
9
11
|
controllers: [RoleController],
|
|
10
12
|
exports: [RoleService],
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { UserGroupDomainError } from '../../userGroup/user-group.errors';
|
|
2
|
+
import { UserGroupProvider } from './user-group.provider';
|
|
3
|
+
|
|
4
|
+
function createHarness() {
|
|
5
|
+
const groups = {
|
|
6
|
+
search: jest.fn(),
|
|
7
|
+
resolveUsers: jest.fn(),
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
groups,
|
|
11
|
+
provider: new UserGroupProvider(groups as never),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('UserGroupProvider', () => {
|
|
16
|
+
it('returns the active state supplied by the user group service', async () => {
|
|
17
|
+
const { groups, provider } = createHarness();
|
|
18
|
+
groups.search.mockResolvedValue([
|
|
19
|
+
{
|
|
20
|
+
code: 'finance',
|
|
21
|
+
name: 'Finance',
|
|
22
|
+
description: null,
|
|
23
|
+
isActive: false,
|
|
24
|
+
revision: 2,
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
await expect(provider.search('', { userId: 'admin' })).resolves.toEqual([
|
|
29
|
+
expect.objectContaining({ ref: 'finance', active: false }),
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('preserves domain errors while resolving a user group', async () => {
|
|
34
|
+
const { groups, provider } = createHarness();
|
|
35
|
+
const error = new UserGroupDomainError(
|
|
36
|
+
'USER_GROUP_NOT_FOUND',
|
|
37
|
+
'User group not found: missing',
|
|
38
|
+
404,
|
|
39
|
+
);
|
|
40
|
+
groups.resolveUsers.mockRejectedValue(error);
|
|
41
|
+
|
|
42
|
+
await expect(
|
|
43
|
+
provider.resolve(['missing'], { actor: { userId: 'admin' } }),
|
|
44
|
+
).rejects.toBe(error);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -62,7 +62,7 @@ export class UserGroupProvider implements SubjectProvider {
|
|
|
62
62
|
ref: group.code,
|
|
63
63
|
label: group.name,
|
|
64
64
|
...(group.description ? { description: group.description } : {}),
|
|
65
|
-
active:
|
|
65
|
+
active: group.isActive,
|
|
66
66
|
revision: group.revision,
|
|
67
67
|
}));
|
|
68
68
|
} catch (error) {
|
|
@@ -177,7 +177,8 @@ export class UserGroupProvider implements SubjectProvider {
|
|
|
177
177
|
);
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
} catch {
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (error instanceof UserGroupDomainError) throw error;
|
|
181
182
|
throw new SubjectProviderUnavailableError(this.key);
|
|
182
183
|
}
|
|
183
184
|
return [...principals.values()].sort((a, b) =>
|
|
@@ -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
|
UserWhereSelect,
|
|
44
47
|
} from '../../generated/user/dto/user-types.dto';
|
|
45
48
|
import { UserEntity } from '../../generated/user/entities/user.entity';
|
|
49
|
+
import { AllowUnauthorizedRequest } from '../../lib/auth.guard';
|
|
50
|
+
import { ImportPayloadDto } from '../permTransfer/perm-transfer.dto';
|
|
51
|
+
import { UserTransferService } from '../permTransfer/user-transfer.service';
|
|
46
52
|
import { UserService } from './user.service';
|
|
47
53
|
|
|
48
54
|
import { ConfigService } from '@nestjs/config';
|
|
@@ -55,6 +61,7 @@ import * as path from 'path';
|
|
|
55
61
|
export class UserController {
|
|
56
62
|
constructor(
|
|
57
63
|
private readonly userService: UserService,
|
|
64
|
+
private readonly userTransferService: UserTransferService,
|
|
58
65
|
private readonly config: ConfigService,
|
|
59
66
|
@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
|
|
60
67
|
) {
|
|
@@ -186,6 +193,54 @@ export class UserController {
|
|
|
186
193
|
return this.userService.deletePerson(id);
|
|
187
194
|
}
|
|
188
195
|
|
|
196
|
+
// ─── Export/Import (cross-environment transfer) ────────────────────────────
|
|
197
|
+
|
|
198
|
+
@Post(':userid/export-token')
|
|
199
|
+
@UseRoles({
|
|
200
|
+
resource: 'user',
|
|
201
|
+
action: 'read',
|
|
202
|
+
possession: 'any',
|
|
203
|
+
})
|
|
204
|
+
async generateExportToken(@Param('userid') userid: string, @Req() req) {
|
|
205
|
+
const baseUrl = `${req.protocol}://${req.get('host')}/api`;
|
|
206
|
+
return this.userTransferService.generateExportToken(userid, baseUrl);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@Get('export/:userid')
|
|
210
|
+
@AllowUnauthorizedRequest()
|
|
211
|
+
async getExportPayload(
|
|
212
|
+
@Param('userid') userid: string,
|
|
213
|
+
@Query('token') token: string,
|
|
214
|
+
) {
|
|
215
|
+
if (!token) {
|
|
216
|
+
throw new UnauthorizedException('Export token is required');
|
|
217
|
+
}
|
|
218
|
+
return this.userTransferService.getExportPayload(userid, token);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@Post('import-preview')
|
|
222
|
+
@UseRoles({
|
|
223
|
+
resource: 'user',
|
|
224
|
+
action: 'update',
|
|
225
|
+
possession: 'any',
|
|
226
|
+
})
|
|
227
|
+
async importPreview(@Body() dto: ImportPayloadDto) {
|
|
228
|
+
return this.userTransferService.importPreview(dto.payload);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@Post('import-confirm')
|
|
232
|
+
@UseRoles({
|
|
233
|
+
resource: 'user',
|
|
234
|
+
action: 'update',
|
|
235
|
+
possession: 'any',
|
|
236
|
+
})
|
|
237
|
+
async importConfirm(@Body() dto: ImportPayloadDto, @Req() req) {
|
|
238
|
+
return this.userTransferService.importConfirm(
|
|
239
|
+
dto.payload,
|
|
240
|
+
req.user.username ?? req.user.userid,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
189
244
|
@Post('upload')
|
|
190
245
|
@UseRoles({
|
|
191
246
|
resource: 'user',
|
package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.module.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Module } from '@nestjs/common';
|
|
2
|
+
import { PermTransferModule } from '../permTransfer/perm-transfer.module';
|
|
2
3
|
import { UserController } from './user.controller';
|
|
3
4
|
import { UserService } from './user.service';
|
|
4
5
|
|
|
5
6
|
@Module({
|
|
7
|
+
imports: [PermTransferModule],
|
|
6
8
|
controllers: [UserController],
|
|
7
9
|
providers: [UserService],
|
|
8
10
|
exports: [UserService],
|
|
@@ -677,6 +677,57 @@ describe('WorkflowCompilerService', () => {
|
|
|
677
677
|
});
|
|
678
678
|
});
|
|
679
679
|
|
|
680
|
+
it('validates the failure callback connection on an event trigger', async () => {
|
|
681
|
+
const findConnection = jest.fn().mockResolvedValue({ isEnabled: true });
|
|
682
|
+
const prisma = {
|
|
683
|
+
workflowNodeType: {
|
|
684
|
+
findMany: jest.fn().mockResolvedValue([
|
|
685
|
+
{
|
|
686
|
+
id: BigInt(8),
|
|
687
|
+
type: 'event_trigger',
|
|
688
|
+
runtimeKey: 'event_trigger',
|
|
689
|
+
instancePolicy: 'OPTIONAL',
|
|
690
|
+
schemaVersion: 6,
|
|
691
|
+
configSchema: { type: 'object' },
|
|
692
|
+
uiSchema: {},
|
|
693
|
+
},
|
|
694
|
+
]),
|
|
695
|
+
},
|
|
696
|
+
workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
|
|
697
|
+
integrationConnection: { findUnique: findConnection },
|
|
698
|
+
};
|
|
699
|
+
const service = new WorkflowCompilerService(
|
|
700
|
+
prisma as any,
|
|
701
|
+
{ validateOrThrow: jest.fn() } as any,
|
|
702
|
+
{ assertUiSchemaSupported: jest.fn() } as any,
|
|
703
|
+
{ validateSubjects: jest.fn() } as any,
|
|
704
|
+
);
|
|
705
|
+
|
|
706
|
+
await service.compile(
|
|
707
|
+
{
|
|
708
|
+
nodes: [
|
|
709
|
+
{
|
|
710
|
+
id: 'event',
|
|
711
|
+
type: 'event_trigger',
|
|
712
|
+
config: {
|
|
713
|
+
failureCallback: {
|
|
714
|
+
connectionRef: 'hardware-service',
|
|
715
|
+
path: '/api/hardware-disposal/workflow-failed',
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
},
|
|
719
|
+
],
|
|
720
|
+
edges: [],
|
|
721
|
+
},
|
|
722
|
+
{ userId: 'author' },
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
expect(findConnection).toHaveBeenCalledWith({
|
|
726
|
+
where: { code: 'hardware-service' },
|
|
727
|
+
select: { isEnabled: true },
|
|
728
|
+
});
|
|
729
|
+
});
|
|
730
|
+
|
|
680
731
|
it('validates required inputs from the selected published version', async () => {
|
|
681
732
|
const findWorkflow = jest.fn().mockResolvedValue({
|
|
682
733
|
status: 'PUBLISHED',
|
|
@@ -898,7 +949,7 @@ describe('WorkflowCompilerService', () => {
|
|
|
898
949
|
).resolves.toBeUndefined();
|
|
899
950
|
});
|
|
900
951
|
|
|
901
|
-
it('rejects
|
|
952
|
+
it('rejects legacy raw SQL database configuration', async () => {
|
|
902
953
|
const prisma = {
|
|
903
954
|
workflowNodeType: {
|
|
904
955
|
findMany: jest.fn().mockResolvedValue([
|
|
@@ -907,7 +958,7 @@ describe('WorkflowCompilerService', () => {
|
|
|
907
958
|
type: 'db_execute',
|
|
908
959
|
runtimeKey: 'db_execute',
|
|
909
960
|
instancePolicy: 'INLINE_ONLY',
|
|
910
|
-
schemaVersion:
|
|
961
|
+
schemaVersion: 5,
|
|
911
962
|
configSchema: { type: 'object' },
|
|
912
963
|
uiSchema: {},
|
|
913
964
|
},
|
|
@@ -930,8 +981,8 @@ describe('WorkflowCompilerService', () => {
|
|
|
930
981
|
id: 'database-1',
|
|
931
982
|
type: 'db_execute',
|
|
932
983
|
config: {
|
|
933
|
-
allowWrite:
|
|
934
|
-
sql: '
|
|
984
|
+
allowWrite: true,
|
|
985
|
+
sql: 'UPDATE users SET active = false',
|
|
935
986
|
},
|
|
936
987
|
},
|
|
937
988
|
],
|
|
@@ -941,13 +992,13 @@ describe('WorkflowCompilerService', () => {
|
|
|
941
992
|
),
|
|
942
993
|
).rejects.toMatchObject({
|
|
943
994
|
response: {
|
|
944
|
-
message: '
|
|
995
|
+
message: '数据库节点不再支持 SQL,请选择 workflow_api 中的 Function',
|
|
945
996
|
nodeId: 'database-1',
|
|
946
997
|
},
|
|
947
998
|
});
|
|
948
999
|
});
|
|
949
1000
|
|
|
950
|
-
it('accepts a
|
|
1001
|
+
it('accepts a registered workflow_api Function with matching arguments', async () => {
|
|
951
1002
|
const prisma = {
|
|
952
1003
|
workflowNodeType: {
|
|
953
1004
|
findMany: jest.fn().mockResolvedValue([
|
|
@@ -963,6 +1014,18 @@ describe('WorkflowCompilerService', () => {
|
|
|
963
1014
|
]),
|
|
964
1015
|
},
|
|
965
1016
|
workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
|
|
1017
|
+
$queryRaw: jest.fn().mockResolvedValue([
|
|
1018
|
+
{
|
|
1019
|
+
schema: 'workflow_api',
|
|
1020
|
+
name: 'approve_request',
|
|
1021
|
+
identity_arguments: 'p_request_id bigint, p_approved boolean',
|
|
1022
|
+
return_type: 'jsonb',
|
|
1023
|
+
arguments: [
|
|
1024
|
+
{ position: 1, name: 'p_request_id', type: 'bigint' },
|
|
1025
|
+
{ position: 2, name: 'p_approved', type: 'boolean' },
|
|
1026
|
+
],
|
|
1027
|
+
},
|
|
1028
|
+
]),
|
|
966
1029
|
};
|
|
967
1030
|
const service = new WorkflowCompilerService(
|
|
968
1031
|
prisma as any,
|
|
@@ -979,8 +1042,15 @@ describe('WorkflowCompilerService', () => {
|
|
|
979
1042
|
id: 'database-1',
|
|
980
1043
|
type: 'db_execute',
|
|
981
1044
|
config: {
|
|
982
|
-
|
|
983
|
-
|
|
1045
|
+
functionRef: {
|
|
1046
|
+
schema: 'workflow_api',
|
|
1047
|
+
name: 'approve_request',
|
|
1048
|
+
identityArguments: 'p_request_id bigint, p_approved boolean',
|
|
1049
|
+
},
|
|
1050
|
+
argumentBindings: [
|
|
1051
|
+
{ source: 'INPUT', path: 'requestId' },
|
|
1052
|
+
{ source: 'FIXED', valueType: 'BOOLEAN', value: 'true' },
|
|
1053
|
+
],
|
|
984
1054
|
},
|
|
985
1055
|
},
|
|
986
1056
|
],
|
|
@@ -992,13 +1062,17 @@ describe('WorkflowCompilerService', () => {
|
|
|
992
1062
|
nodes: [
|
|
993
1063
|
expect.objectContaining({
|
|
994
1064
|
id: 'database-1',
|
|
995
|
-
config: expect.objectContaining({
|
|
1065
|
+
config: expect.objectContaining({
|
|
1066
|
+
functionRef: expect.objectContaining({
|
|
1067
|
+
name: 'approve_request',
|
|
1068
|
+
}),
|
|
1069
|
+
}),
|
|
996
1070
|
}),
|
|
997
1071
|
],
|
|
998
1072
|
});
|
|
999
1073
|
});
|
|
1000
1074
|
|
|
1001
|
-
it('
|
|
1075
|
+
it('rejects a Function whose signature is not in the database catalog', async () => {
|
|
1002
1076
|
const prisma = {
|
|
1003
1077
|
workflowNodeType: {
|
|
1004
1078
|
findMany: jest.fn().mockResolvedValue([
|
|
@@ -1014,6 +1088,7 @@ describe('WorkflowCompilerService', () => {
|
|
|
1014
1088
|
]),
|
|
1015
1089
|
},
|
|
1016
1090
|
workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
|
|
1091
|
+
$queryRaw: jest.fn().mockResolvedValue([]),
|
|
1017
1092
|
};
|
|
1018
1093
|
const service = new WorkflowCompilerService(
|
|
1019
1094
|
prisma as any,
|
|
@@ -1030,8 +1105,12 @@ describe('WorkflowCompilerService', () => {
|
|
|
1030
1105
|
id: 'database-1',
|
|
1031
1106
|
type: 'db_execute',
|
|
1032
1107
|
config: {
|
|
1033
|
-
|
|
1034
|
-
|
|
1108
|
+
functionRef: {
|
|
1109
|
+
schema: 'workflow_api',
|
|
1110
|
+
name: 'missing_function',
|
|
1111
|
+
identityArguments: 'p_id bigint',
|
|
1112
|
+
},
|
|
1113
|
+
argumentBindings: [{ source: 'INPUT', path: 'id' }],
|
|
1035
1114
|
},
|
|
1036
1115
|
},
|
|
1037
1116
|
],
|
|
@@ -1039,8 +1118,11 @@ describe('WorkflowCompilerService', () => {
|
|
|
1039
1118
|
},
|
|
1040
1119
|
{ userId: 'author' },
|
|
1041
1120
|
),
|
|
1042
|
-
).
|
|
1043
|
-
|
|
1121
|
+
).rejects.toMatchObject({
|
|
1122
|
+
response: {
|
|
1123
|
+
message: '选择的数据库 Function 不存在或已不再开放给 Workflow',
|
|
1124
|
+
nodeId: 'database-1',
|
|
1125
|
+
},
|
|
1044
1126
|
});
|
|
1045
1127
|
});
|
|
1046
1128
|
});
|