@flusys/nestjs-iam 6.0.1 → 6.1.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/cjs/controllers/action.controller.js +17 -9
- package/cjs/controllers/action.controller.spec.js +79 -0
- package/cjs/controllers/company-action-permission.controller.spec.js +65 -0
- package/cjs/controllers/my-permission.controller.spec.js +56 -0
- package/cjs/controllers/role-permission.controller.spec.js +140 -0
- package/cjs/controllers/role.controller.spec.js +86 -0
- package/cjs/controllers/user-action-permission.controller.js +0 -3
- package/cjs/controllers/user-action-permission.controller.spec.js +68 -0
- package/cjs/docs/iam-swagger.config.js +6 -0
- package/cjs/docs/iam-swagger.config.spec.js +99 -0
- package/cjs/dtos/action.dto.js +17 -0
- package/cjs/entities/index.spec.js +56 -0
- package/cjs/helpers/company-access.helper.spec.js +68 -0
- package/cjs/helpers/permission-mode.helper.spec.js +54 -0
- package/cjs/modules/iam.module.js +3 -1
- package/cjs/modules/iam.module.spec.js +293 -0
- package/cjs/services/action.service.js +90 -7
- package/cjs/services/action.service.spec.js +314 -0
- package/cjs/services/iam-config.service.spec.js +110 -0
- package/cjs/services/iam-datasource.service.spec.js +117 -0
- package/cjs/services/permission-cache.service.js +113 -110
- package/cjs/services/permission-cache.service.spec.js +252 -0
- package/cjs/services/permission.service.js +213 -92
- package/cjs/services/permission.service.spec.js +967 -0
- package/cjs/services/role.service.js +47 -3
- package/cjs/services/role.service.spec.js +312 -0
- package/controllers/action.controller.d.ts +5 -3
- package/dtos/action.dto.d.ts +3 -0
- package/entities/index.d.ts +2 -2
- package/fesm/controllers/action.controller.js +18 -10
- package/fesm/controllers/action.controller.spec.js +75 -0
- package/fesm/controllers/company-action-permission.controller.spec.js +61 -0
- package/fesm/controllers/my-permission.controller.spec.js +52 -0
- package/fesm/controllers/role-permission.controller.spec.js +136 -0
- package/fesm/controllers/role.controller.spec.js +82 -0
- package/fesm/controllers/user-action-permission.controller.js +0 -3
- package/fesm/controllers/user-action-permission.controller.spec.js +64 -0
- package/fesm/docs/iam-swagger.config.js +6 -0
- package/fesm/docs/iam-swagger.config.spec.js +95 -0
- package/fesm/dtos/action.dto.js +14 -0
- package/fesm/entities/index.spec.js +52 -0
- package/fesm/helpers/company-access.helper.spec.js +64 -0
- package/fesm/helpers/permission-mode.helper.spec.js +50 -0
- package/fesm/modules/iam.module.js +4 -2
- package/fesm/modules/iam.module.spec.js +289 -0
- package/fesm/services/action.service.js +90 -7
- package/fesm/services/action.service.spec.js +310 -0
- package/fesm/services/iam-config.service.spec.js +106 -0
- package/fesm/services/iam-datasource.service.spec.js +113 -0
- package/fesm/services/permission-cache.service.js +101 -108
- package/fesm/services/permission-cache.service.spec.js +248 -0
- package/fesm/services/permission.service.js +213 -92
- package/fesm/services/permission.service.spec.js +963 -0
- package/fesm/services/role.service.js +48 -4
- package/fesm/services/role.service.spec.js +308 -0
- package/package.json +3 -3
- package/services/action.service.d.ts +7 -3
- package/services/permission-cache.service.d.ts +13 -19
- package/services/permission.service.d.ts +6 -3
- package/services/role.service.d.ts +7 -3
|
@@ -14,7 +14,7 @@ import { PermissionModeHelper } from '../helpers';
|
|
|
14
14
|
import { ActionService, PermissionService, RoleService } from '../services';
|
|
15
15
|
import { IAMConfigService } from '../services/iam-config.service';
|
|
16
16
|
import { IAMDataSourceService } from '../services/iam-datasource.service';
|
|
17
|
-
import { PermissionCacheService } from '../services/permission-cache.service';
|
|
17
|
+
import { MY_PERMISSIONS_CACHE_PREFIX, PermissionCacheService } from '../services/permission-cache.service';
|
|
18
18
|
export class IAMModule {
|
|
19
19
|
static getControllers(permissionMode, enableCompanyFeature) {
|
|
20
20
|
const baseControllers = [
|
|
@@ -58,7 +58,9 @@ export class IAMModule {
|
|
|
58
58
|
return {
|
|
59
59
|
provide: PERMISSION_GUARD_CONFIG,
|
|
60
60
|
useValue: {
|
|
61
|
-
enableCompanyFeature
|
|
61
|
+
enableCompanyFeature,
|
|
62
|
+
userPermissionKeyFormat: `${MY_PERMISSIONS_CACHE_PREFIX}:user:{userId}`,
|
|
63
|
+
companyPermissionKeyFormat: `${MY_PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`
|
|
62
64
|
}
|
|
63
65
|
};
|
|
64
66
|
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
import { PERMISSION_GUARD_CONFIG } from '@flusys/nestjs-shared';
|
|
15
|
+
import { IAMModule } from './iam.module';
|
|
16
|
+
import { IAM_MODULE_OPTIONS } from '../config/iam.constants';
|
|
17
|
+
import { ActionController, CompanyActionPermissionController, MyPermissionController, RoleController, RolePermissionController, UserActionPermissionController } from '../controllers';
|
|
18
|
+
import { ActionService, PermissionService, RoleService } from '../services';
|
|
19
|
+
import { IAMConfigService } from '../services/iam-config.service';
|
|
20
|
+
import { IAMDataSourceService } from '../services/iam-datasource.service';
|
|
21
|
+
import { PermissionCacheService } from '../services/permission-cache.service';
|
|
22
|
+
function providerTokens(providers) {
|
|
23
|
+
return providers.map((p)=>typeof p === 'function' ? p : p.provide);
|
|
24
|
+
}
|
|
25
|
+
describe('IAMModule', ()=>{
|
|
26
|
+
describe('forRoot - controller/service registration matrix', ()=>{
|
|
27
|
+
it('should register no controllers by default (includeController defaults to false)', ()=>{
|
|
28
|
+
const dynamicModule = IAMModule.forRoot();
|
|
29
|
+
expect(dynamicModule.controllers).toEqual([]);
|
|
30
|
+
});
|
|
31
|
+
it('DIRECT mode: registers only UserActionPermissionController beyond the base set', ()=>{
|
|
32
|
+
const dynamicModule = IAMModule.forRoot({
|
|
33
|
+
includeController: true,
|
|
34
|
+
bootstrapAppConfig: {
|
|
35
|
+
permissionMode: 'DIRECT'
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
expect(dynamicModule.controllers).toEqual([
|
|
39
|
+
ActionController,
|
|
40
|
+
MyPermissionController,
|
|
41
|
+
UserActionPermissionController
|
|
42
|
+
]);
|
|
43
|
+
expect(providerTokens(dynamicModule.providers)).not.toContain(RoleService);
|
|
44
|
+
});
|
|
45
|
+
it('RBAC mode: registers RoleController + RolePermissionController but not UserActionPermissionController', ()=>{
|
|
46
|
+
const dynamicModule = IAMModule.forRoot({
|
|
47
|
+
includeController: true,
|
|
48
|
+
bootstrapAppConfig: {
|
|
49
|
+
permissionMode: 'RBAC'
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
expect(dynamicModule.controllers).toEqual([
|
|
53
|
+
ActionController,
|
|
54
|
+
MyPermissionController,
|
|
55
|
+
RoleController,
|
|
56
|
+
RolePermissionController
|
|
57
|
+
]);
|
|
58
|
+
expect(providerTokens(dynamicModule.providers)).toContain(RoleService);
|
|
59
|
+
});
|
|
60
|
+
it('FULL mode: registers every permission controller', ()=>{
|
|
61
|
+
const dynamicModule = IAMModule.forRoot({
|
|
62
|
+
includeController: true,
|
|
63
|
+
bootstrapAppConfig: {
|
|
64
|
+
permissionMode: 'FULL'
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
expect(dynamicModule.controllers).toEqual([
|
|
68
|
+
ActionController,
|
|
69
|
+
MyPermissionController,
|
|
70
|
+
RoleController,
|
|
71
|
+
UserActionPermissionController,
|
|
72
|
+
RolePermissionController
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
it('defaults to FULL mode when permissionMode is omitted', ()=>{
|
|
76
|
+
const dynamicModule = IAMModule.forRoot({
|
|
77
|
+
includeController: true
|
|
78
|
+
});
|
|
79
|
+
expect(dynamicModule.controllers).toEqual(expect.arrayContaining([
|
|
80
|
+
RoleController,
|
|
81
|
+
UserActionPermissionController,
|
|
82
|
+
RolePermissionController
|
|
83
|
+
]));
|
|
84
|
+
});
|
|
85
|
+
it('defaults to FULL mode when permissionMode is an unrecognized string', ()=>{
|
|
86
|
+
const dynamicModule = IAMModule.forRoot({
|
|
87
|
+
includeController: true,
|
|
88
|
+
bootstrapAppConfig: {
|
|
89
|
+
permissionMode: 'BOGUS'
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
expect(dynamicModule.controllers).toEqual(expect.arrayContaining([
|
|
93
|
+
RoleController,
|
|
94
|
+
UserActionPermissionController,
|
|
95
|
+
RolePermissionController
|
|
96
|
+
]));
|
|
97
|
+
});
|
|
98
|
+
it('adds CompanyActionPermissionController only when enableCompanyFeature is true', ()=>{
|
|
99
|
+
const withCompany = IAMModule.forRoot({
|
|
100
|
+
includeController: true,
|
|
101
|
+
bootstrapAppConfig: {
|
|
102
|
+
enableCompanyFeature: true
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const withoutCompany = IAMModule.forRoot({
|
|
106
|
+
includeController: true,
|
|
107
|
+
bootstrapAppConfig: {
|
|
108
|
+
enableCompanyFeature: false
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
expect(withCompany.controllers).toContain(CompanyActionPermissionController);
|
|
112
|
+
expect(withoutCompany.controllers).not.toContain(CompanyActionPermissionController);
|
|
113
|
+
});
|
|
114
|
+
it('excludes RoleService for DIRECT mode but includes it for RBAC/FULL', ()=>{
|
|
115
|
+
const direct = IAMModule.forRoot({
|
|
116
|
+
bootstrapAppConfig: {
|
|
117
|
+
permissionMode: 'DIRECT'
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
const rbac = IAMModule.forRoot({
|
|
121
|
+
bootstrapAppConfig: {
|
|
122
|
+
permissionMode: 'RBAC'
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const full = IAMModule.forRoot({
|
|
126
|
+
bootstrapAppConfig: {
|
|
127
|
+
permissionMode: 'FULL'
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
expect(providerTokens(direct.providers)).not.toContain(RoleService);
|
|
131
|
+
expect(providerTokens(rbac.providers)).toContain(RoleService);
|
|
132
|
+
expect(providerTokens(full.providers)).toContain(RoleService);
|
|
133
|
+
expect(providerTokens(direct.exports)).not.toContain(RoleService);
|
|
134
|
+
expect(providerTokens(rbac.exports)).toContain(RoleService);
|
|
135
|
+
});
|
|
136
|
+
it('always registers the base providers/exports (ActionService, PermissionService, PermissionCacheService)', ()=>{
|
|
137
|
+
const dynamicModule = IAMModule.forRoot();
|
|
138
|
+
expect(providerTokens(dynamicModule.providers)).toEqual(expect.arrayContaining([
|
|
139
|
+
IAMConfigService,
|
|
140
|
+
IAMDataSourceService,
|
|
141
|
+
ActionService,
|
|
142
|
+
PermissionService,
|
|
143
|
+
PermissionCacheService
|
|
144
|
+
]));
|
|
145
|
+
expect(dynamicModule.exports).toEqual(expect.arrayContaining([
|
|
146
|
+
IAMConfigService,
|
|
147
|
+
IAMDataSourceService,
|
|
148
|
+
ActionService,
|
|
149
|
+
PermissionService,
|
|
150
|
+
PermissionCacheService,
|
|
151
|
+
PERMISSION_GUARD_CONFIG
|
|
152
|
+
]));
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
describe('forRoot - options/global handling', ()=>{
|
|
156
|
+
it('should not set `global` on the returned module when global is false/omitted', ()=>{
|
|
157
|
+
const dynamicModule = IAMModule.forRoot();
|
|
158
|
+
expect(dynamicModule.global).toBeUndefined();
|
|
159
|
+
});
|
|
160
|
+
it('should set global: true when requested', ()=>{
|
|
161
|
+
const dynamicModule = IAMModule.forRoot({
|
|
162
|
+
global: true
|
|
163
|
+
});
|
|
164
|
+
expect(dynamicModule.global).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
it('should register IAM_MODULE_OPTIONS with the given options', ()=>{
|
|
167
|
+
const options = {
|
|
168
|
+
includeController: true
|
|
169
|
+
};
|
|
170
|
+
const dynamicModule = IAMModule.forRoot(options);
|
|
171
|
+
const provider = dynamicModule.providers.find((p)=>p.provide === IAM_MODULE_OPTIONS);
|
|
172
|
+
expect(provider.useValue).toBe(options);
|
|
173
|
+
});
|
|
174
|
+
it('should build a company-aware PERMISSION_GUARD_CONFIG provider', ()=>{
|
|
175
|
+
const dynamicModule = IAMModule.forRoot({
|
|
176
|
+
bootstrapAppConfig: {
|
|
177
|
+
enableCompanyFeature: true
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
const provider = dynamicModule.providers.find((p)=>p.provide === PERMISSION_GUARD_CONFIG);
|
|
181
|
+
expect(provider.useValue.enableCompanyFeature).toBe(true);
|
|
182
|
+
expect(provider.useValue.userPermissionKeyFormat).toContain('{userId}');
|
|
183
|
+
expect(provider.useValue.companyPermissionKeyFormat).toContain('{companyId}');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
describe('forRootAsync', ()=>{
|
|
187
|
+
it('mirrors the controller/service registration matrix of forRoot', ()=>{
|
|
188
|
+
const dynamicModule = IAMModule.forRootAsync({
|
|
189
|
+
includeController: true,
|
|
190
|
+
bootstrapAppConfig: {
|
|
191
|
+
permissionMode: 'DIRECT'
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
expect(dynamicModule.controllers).toEqual([
|
|
195
|
+
ActionController,
|
|
196
|
+
MyPermissionController,
|
|
197
|
+
UserActionPermissionController
|
|
198
|
+
]);
|
|
199
|
+
});
|
|
200
|
+
it('should forward external imports alongside CacheModule/UtilsModule', ()=>{
|
|
201
|
+
let FakeImportedModule = class FakeImportedModule {
|
|
202
|
+
};
|
|
203
|
+
const dynamicModule = IAMModule.forRootAsync({
|
|
204
|
+
imports: [
|
|
205
|
+
FakeImportedModule
|
|
206
|
+
]
|
|
207
|
+
});
|
|
208
|
+
expect(dynamicModule.imports).toEqual(expect.arrayContaining([
|
|
209
|
+
FakeImportedModule
|
|
210
|
+
]));
|
|
211
|
+
});
|
|
212
|
+
it('useFactory: registers a single options provider using the given inject tokens', async ()=>{
|
|
213
|
+
const useFactory = jest.fn().mockResolvedValue({
|
|
214
|
+
foo: 'bar'
|
|
215
|
+
});
|
|
216
|
+
const dynamicModule = IAMModule.forRootAsync({
|
|
217
|
+
useFactory,
|
|
218
|
+
inject: [
|
|
219
|
+
'SOME_TOKEN'
|
|
220
|
+
]
|
|
221
|
+
});
|
|
222
|
+
const optionsProviders = dynamicModule.providers.filter((p)=>p.provide === IAM_MODULE_OPTIONS);
|
|
223
|
+
expect(optionsProviders).toHaveLength(1);
|
|
224
|
+
const provider = optionsProviders[0];
|
|
225
|
+
expect(provider.useFactory).toBe(useFactory);
|
|
226
|
+
expect(provider.inject).toEqual([
|
|
227
|
+
'SOME_TOKEN'
|
|
228
|
+
]);
|
|
229
|
+
});
|
|
230
|
+
it('useClass: registers both the class provider and an options provider that calls createIAMOptions()', async ()=>{
|
|
231
|
+
let MyOptionsFactory = class MyOptionsFactory {
|
|
232
|
+
constructor(){
|
|
233
|
+
_define_property(this, "createIAMOptions", jest.fn().mockResolvedValue({
|
|
234
|
+
foo: 'from-class'
|
|
235
|
+
}));
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const dynamicModule = IAMModule.forRootAsync({
|
|
239
|
+
useClass: MyOptionsFactory
|
|
240
|
+
});
|
|
241
|
+
const classProvider = dynamicModule.providers.find((p)=>p.provide === MyOptionsFactory);
|
|
242
|
+
expect(classProvider.useClass).toBe(MyOptionsFactory);
|
|
243
|
+
const optionsProvider = dynamicModule.providers.find((p)=>p.provide === IAM_MODULE_OPTIONS);
|
|
244
|
+
expect(optionsProvider.inject).toEqual([
|
|
245
|
+
MyOptionsFactory
|
|
246
|
+
]);
|
|
247
|
+
const instance = new MyOptionsFactory();
|
|
248
|
+
const resolved = await optionsProvider.useFactory(instance);
|
|
249
|
+
expect(instance.createIAMOptions).toHaveBeenCalled();
|
|
250
|
+
expect(resolved).toEqual({
|
|
251
|
+
foo: 'from-class'
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
it('useExisting: registers a single options provider injecting the existing factory', async ()=>{
|
|
255
|
+
let MyOptionsFactory = class MyOptionsFactory {
|
|
256
|
+
constructor(){
|
|
257
|
+
_define_property(this, "createIAMOptions", jest.fn().mockResolvedValue({
|
|
258
|
+
foo: 'from-existing'
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const dynamicModule = IAMModule.forRootAsync({
|
|
263
|
+
useExisting: MyOptionsFactory
|
|
264
|
+
});
|
|
265
|
+
const optionsProviders = dynamicModule.providers.filter((p)=>p.provide === IAM_MODULE_OPTIONS);
|
|
266
|
+
expect(optionsProviders).toHaveLength(1);
|
|
267
|
+
const provider = optionsProviders[0];
|
|
268
|
+
expect(provider.inject).toEqual([
|
|
269
|
+
MyOptionsFactory
|
|
270
|
+
]);
|
|
271
|
+
const instance = new MyOptionsFactory();
|
|
272
|
+
const resolved = await provider.useFactory(instance);
|
|
273
|
+
expect(resolved).toEqual({
|
|
274
|
+
foo: 'from-existing'
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
describe('forFeature', ()=>{
|
|
279
|
+
it('should behave identically to forRoot', ()=>{
|
|
280
|
+
const options = {
|
|
281
|
+
includeController: true,
|
|
282
|
+
bootstrapAppConfig: {
|
|
283
|
+
permissionMode: 'RBAC'
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
expect(IAMModule.forFeature(options)).toEqual(IAMModule.forRoot(options));
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
});
|
|
@@ -31,10 +31,90 @@ import { BadRequestException, Inject, Injectable, Scope } from '@nestjs/common';
|
|
|
31
31
|
import { In } from 'typeorm';
|
|
32
32
|
import { PERMISSION_OPERATION_MESSAGES } from '../config';
|
|
33
33
|
import { Action } from '../entities/action.entity';
|
|
34
|
+
import { UserIamPermissionWithCompany } from '../entities/permission-with-company.entity';
|
|
35
|
+
import { UserIamPermission } from '../entities/user-iam-permission.entity';
|
|
36
|
+
import { IamEntityType } from '../enums/iam-entity-type.enum';
|
|
37
|
+
import { IamPermissionType } from '../enums/iam-permission-type.enum';
|
|
34
38
|
import { IAMConfigService } from './iam-config.service';
|
|
35
39
|
import { IAMDataSourceService } from './iam-datasource.service';
|
|
40
|
+
import { PermissionCacheService } from './permission-cache.service';
|
|
36
41
|
import { PermissionService } from './permission.service';
|
|
37
42
|
export class ActionService extends ApiService {
|
|
43
|
+
async beforeDeleteOperation(dto, user, queryRunner) {
|
|
44
|
+
const actionIds = Array.isArray(dto.id) ? dto.id : [
|
|
45
|
+
dto.id
|
|
46
|
+
];
|
|
47
|
+
if (actionIds.length === 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
51
|
+
const permissionEntity = enableCompanyFeature ? UserIamPermissionWithCompany : UserIamPermission;
|
|
52
|
+
const permissionRepo = queryRunner.manager.getRepository(permissionEntity);
|
|
53
|
+
const [roleActionRows, userActionRows, companyActionRows] = await Promise.all([
|
|
54
|
+
permissionRepo.find({
|
|
55
|
+
where: {
|
|
56
|
+
permissionType: IamPermissionType.ROLE_ACTION,
|
|
57
|
+
sourceType: IamEntityType.ROLE,
|
|
58
|
+
targetType: IamEntityType.ACTION,
|
|
59
|
+
targetId: In(actionIds)
|
|
60
|
+
}
|
|
61
|
+
}),
|
|
62
|
+
permissionRepo.find({
|
|
63
|
+
where: {
|
|
64
|
+
permissionType: IamPermissionType.USER_ACTION,
|
|
65
|
+
targetType: IamEntityType.ACTION,
|
|
66
|
+
targetId: In(actionIds)
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
enableCompanyFeature ? permissionRepo.find({
|
|
70
|
+
where: {
|
|
71
|
+
permissionType: IamPermissionType.COMPANY_ACTION,
|
|
72
|
+
sourceType: IamEntityType.COMPANY,
|
|
73
|
+
targetType: IamEntityType.ACTION,
|
|
74
|
+
targetId: In(actionIds)
|
|
75
|
+
}
|
|
76
|
+
}) : Promise.resolve([])
|
|
77
|
+
]);
|
|
78
|
+
const affectedUserIds = new Set(userActionRows.map((row)=>row.userId).filter((id)=>!!id));
|
|
79
|
+
const affectedCompanyIds = [
|
|
80
|
+
...new Set(companyActionRows.map((row)=>row.sourceId).filter((id)=>!!id))
|
|
81
|
+
];
|
|
82
|
+
const affectedRoleIds = [
|
|
83
|
+
...new Set(roleActionRows.map((row)=>row.sourceId))
|
|
84
|
+
];
|
|
85
|
+
if (affectedRoleIds.length > 0) {
|
|
86
|
+
const userRoleRows = await permissionRepo.find({
|
|
87
|
+
where: {
|
|
88
|
+
permissionType: IamPermissionType.USER_ROLE,
|
|
89
|
+
targetType: IamEntityType.ROLE,
|
|
90
|
+
targetId: In(affectedRoleIds)
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
userRoleRows.forEach((row)=>row.userId && affectedUserIds.add(row.userId));
|
|
94
|
+
}
|
|
95
|
+
await permissionRepo.delete({
|
|
96
|
+
permissionType: IamPermissionType.ROLE_ACTION,
|
|
97
|
+
targetType: IamEntityType.ACTION,
|
|
98
|
+
targetId: In(actionIds)
|
|
99
|
+
});
|
|
100
|
+
await permissionRepo.delete({
|
|
101
|
+
permissionType: IamPermissionType.USER_ACTION,
|
|
102
|
+
targetType: IamEntityType.ACTION,
|
|
103
|
+
targetId: In(actionIds)
|
|
104
|
+
});
|
|
105
|
+
await permissionRepo.delete({
|
|
106
|
+
permissionType: IamPermissionType.COMPANY_ACTION,
|
|
107
|
+
sourceType: IamEntityType.COMPANY,
|
|
108
|
+
targetType: IamEntityType.ACTION,
|
|
109
|
+
targetId: In(actionIds)
|
|
110
|
+
});
|
|
111
|
+
await Promise.all([
|
|
112
|
+
affectedUserIds.size > 0 ? this.permissionCacheService.invalidateUsers([
|
|
113
|
+
...affectedUserIds
|
|
114
|
+
]) : Promise.resolve(),
|
|
115
|
+
...affectedCompanyIds.map((companyId)=>this.permissionService.invalidateCompanyMembersCache(companyId))
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
38
118
|
// Query Customization
|
|
39
119
|
async getSelectQuery(query, _user, select) {
|
|
40
120
|
if (!select?.length) {
|
|
@@ -98,12 +178,13 @@ export class ActionService extends ApiService {
|
|
|
98
178
|
});
|
|
99
179
|
}
|
|
100
180
|
}
|
|
101
|
-
/** Get actions available for permission assignment (filtered by company whitelist) */ async getActionsForPermission(user) {
|
|
181
|
+
/** Get actions available for permission assignment (filtered by company whitelist) */ async getActionsForPermission(user, companyId) {
|
|
102
182
|
await this.ensureDataSourceRepository();
|
|
103
183
|
this.requireUser(user, 'getActionsForPermission');
|
|
104
184
|
let whereClause = {};
|
|
105
|
-
|
|
106
|
-
|
|
185
|
+
const targetCompanyId = companyId || user.companyId;
|
|
186
|
+
if (this.iamConfigService.isCompanyFeatureEnabled() && targetCompanyId) {
|
|
187
|
+
const companyActionIds = await this.permissionService.getCompanyActionIds(targetCompanyId);
|
|
107
188
|
if (companyActionIds.length === 0) {
|
|
108
189
|
return [];
|
|
109
190
|
}
|
|
@@ -166,9 +247,9 @@ export class ActionService extends ApiService {
|
|
|
166
247
|
}
|
|
167
248
|
return rootNodes;
|
|
168
249
|
}
|
|
169
|
-
constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider, permissionService){
|
|
170
|
-
super('action', cacheManager, utilsService, ActionService.name, true, 'iam', Action, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "permissionService", void 0), // Custom Methods
|
|
171
|
-
_define_property(this, "actionSelectFields", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.permissionService = permissionService, this.actionSelectFields = [
|
|
250
|
+
constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider, permissionService, permissionCacheService){
|
|
251
|
+
super('action', cacheManager, utilsService, ActionService.name, true, 'iam', Action, dataSourceProvider), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "permissionService", void 0), _define_property(this, "permissionCacheService", void 0), // Custom Methods
|
|
252
|
+
_define_property(this, "actionSelectFields", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.permissionService = permissionService, this.permissionCacheService = permissionCacheService, this.actionSelectFields = [
|
|
172
253
|
'id',
|
|
173
254
|
'code',
|
|
174
255
|
'name',
|
|
@@ -190,12 +271,14 @@ ActionService = _ts_decorate([
|
|
|
190
271
|
_ts_param(2, Inject(IAMConfigService)),
|
|
191
272
|
_ts_param(3, Inject(IAMDataSourceService)),
|
|
192
273
|
_ts_param(4, Inject(PermissionService)),
|
|
274
|
+
_ts_param(5, Inject(PermissionCacheService)),
|
|
193
275
|
_ts_metadata("design:type", Function),
|
|
194
276
|
_ts_metadata("design:paramtypes", [
|
|
195
277
|
typeof HybridCache === "undefined" ? Object : HybridCache,
|
|
196
278
|
typeof UtilsService === "undefined" ? Object : UtilsService,
|
|
197
279
|
typeof IAMConfigService === "undefined" ? Object : IAMConfigService,
|
|
198
280
|
typeof IAMDataSourceService === "undefined" ? Object : IAMDataSourceService,
|
|
199
|
-
typeof PermissionService === "undefined" ? Object : PermissionService
|
|
281
|
+
typeof PermissionService === "undefined" ? Object : PermissionService,
|
|
282
|
+
typeof PermissionCacheService === "undefined" ? Object : PermissionCacheService
|
|
200
283
|
])
|
|
201
284
|
], ActionService);
|