@flusys/nestjs-iam 6.1.0 → 6.1.1
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/company-action-permission.controller.js +1 -1
- package/cjs/controllers/company-action-permission.controller.spec.js +1 -1
- package/cjs/controllers/user-action-permission.controller.js +1 -1
- package/cjs/controllers/user-action-permission.controller.spec.js +1 -1
- package/cjs/dtos/permission.dto.js +7 -0
- package/cjs/entities/permission-base.entity.js +1 -10
- package/cjs/entities/permission-with-company.entity.js +0 -3
- package/cjs/entities/user-iam-permission.entity.js +0 -3
- package/cjs/modules/iam.module.js +2 -2
- package/cjs/services/action.service.js +4 -4
- package/cjs/services/action.service.spec.js +11 -11
- package/cjs/services/permission-cache.service.js +363 -52
- package/cjs/services/permission-cache.service.spec.js +462 -15
- package/cjs/services/permission.service.js +92 -396
- package/cjs/services/permission.service.spec.js +35 -310
- package/cjs/services/role.service.js +1 -1
- package/cjs/services/role.service.spec.js +4 -7
- package/dtos/permission.dto.d.ts +1 -0
- package/entities/permission-base.entity.d.ts +0 -1
- package/fesm/controllers/company-action-permission.controller.js +1 -1
- package/fesm/controllers/company-action-permission.controller.spec.js +1 -1
- package/fesm/controllers/user-action-permission.controller.js +1 -1
- package/fesm/controllers/user-action-permission.controller.spec.js +1 -1
- package/fesm/dtos/permission.dto.js +7 -0
- package/fesm/entities/permission-base.entity.js +1 -10
- package/fesm/entities/permission-with-company.entity.js +0 -3
- package/fesm/entities/user-iam-permission.entity.js +0 -3
- package/fesm/modules/iam.module.js +4 -4
- package/fesm/services/action.service.js +4 -4
- package/fesm/services/action.service.spec.js +11 -11
- package/fesm/services/permission-cache.service.js +365 -51
- package/fesm/services/permission-cache.service.spec.js +462 -15
- package/fesm/services/permission.service.js +92 -396
- package/fesm/services/permission.service.spec.js +35 -310
- package/fesm/services/role.service.js +1 -1
- package/fesm/services/role.service.spec.js +4 -7
- package/package.json +3 -3
- package/services/permission-cache.service.d.ts +20 -3
- package/services/permission.service.d.ts +2 -16
|
@@ -18,10 +18,8 @@ const _permissionwithcompanyentity = require("../entities/permission-with-compan
|
|
|
18
18
|
const _rolewithcompanyentity = require("../entities/role-with-company.entity");
|
|
19
19
|
const _roleentity = require("../entities/role.entity");
|
|
20
20
|
const _useriampermissionentity = require("../entities/user-iam-permission.entity");
|
|
21
|
-
const _actiontypeenum = require("../enums/action-type.enum");
|
|
22
21
|
const _iamentitytypeenum = require("../enums/iam-entity-type.enum");
|
|
23
22
|
const _iampermissiontypeenum = require("../enums/iam-permission-type.enum");
|
|
24
|
-
const _permissiontypeenum = require("../enums/permission-type.enum");
|
|
25
23
|
const _iamconfigservice = require("./iam-config.service");
|
|
26
24
|
const _iamdatasourceservice = require("./iam-datasource.service");
|
|
27
25
|
const _permissioncacheservice = require("./permission-cache.service");
|
|
@@ -120,7 +118,6 @@ let PermissionService = class PermissionService {
|
|
|
120
118
|
sourceId: dto.userId,
|
|
121
119
|
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
122
120
|
targetId: item.id,
|
|
123
|
-
userId: dto.userId,
|
|
124
121
|
companyId: enableCompanyFeature ? companyId : null,
|
|
125
122
|
branchId: enableCompanyFeature ? branchId : null
|
|
126
123
|
}));
|
|
@@ -155,12 +152,12 @@ let PermissionService = class PermissionService {
|
|
|
155
152
|
const result = await permissionRepo.delete(whereDelete);
|
|
156
153
|
removed = result.affected || 0;
|
|
157
154
|
}
|
|
158
|
-
await this.permissionCacheService.invalidateUser(dto.userId, enableCompanyFeature ? companyId : null, [
|
|
155
|
+
await this.permissionCacheService.invalidateUser(dto.userId, enableCompanyFeature ? companyId : null, enableCompanyFeature ? [
|
|
159
156
|
branchId
|
|
160
|
-
]);
|
|
157
|
+
] : []);
|
|
161
158
|
return this.buildOperationResult(dto.items.length, added, removed);
|
|
162
159
|
}
|
|
163
|
-
async getUserActions(userId,
|
|
160
|
+
async getUserActions(userId, companyId, branchId) {
|
|
164
161
|
const permissionRepo = await this.getPermissionRepository();
|
|
165
162
|
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
166
163
|
const where = {
|
|
@@ -170,7 +167,7 @@ let PermissionService = class PermissionService {
|
|
|
170
167
|
};
|
|
171
168
|
if (enableCompanyFeature) {
|
|
172
169
|
if (companyId) where.companyId = companyId;
|
|
173
|
-
where.branchId = branchId
|
|
170
|
+
if (branchId) where.branchId = branchId;
|
|
174
171
|
}
|
|
175
172
|
const permissions = await permissionRepo.find({
|
|
176
173
|
where
|
|
@@ -184,10 +181,11 @@ let PermissionService = class PermissionService {
|
|
|
184
181
|
const action = actionMap.get(p.targetId);
|
|
185
182
|
return {
|
|
186
183
|
id: p.id,
|
|
187
|
-
userId: p.
|
|
184
|
+
userId: p.sourceId,
|
|
188
185
|
actionId: action.id,
|
|
189
186
|
actionCode: action.code ?? '',
|
|
190
187
|
actionName: action.name,
|
|
188
|
+
companyId: ('companyId' in p ? p.companyId : null) ?? null,
|
|
191
189
|
branchId: ('branchId' in p ? p.branchId : null) ?? null,
|
|
192
190
|
createdAt: p.createdAt
|
|
193
191
|
};
|
|
@@ -241,7 +239,6 @@ let PermissionService = class PermissionService {
|
|
|
241
239
|
sourceId: dto.roleId,
|
|
242
240
|
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
243
241
|
targetId: item.id,
|
|
244
|
-
userId: null,
|
|
245
242
|
companyId: enableCompanyFeature ? roleCompanyId : null,
|
|
246
243
|
branchId: null
|
|
247
244
|
}));
|
|
@@ -271,7 +268,7 @@ let PermissionService = class PermissionService {
|
|
|
271
268
|
});
|
|
272
269
|
removed = result.affected || 0;
|
|
273
270
|
}
|
|
274
|
-
await this.invalidateRoleMembersCache(dto.roleId);
|
|
271
|
+
await this.permissionCacheService.invalidateRoleMembersCache(dto.roleId);
|
|
275
272
|
return this.buildOperationResult(dto.items.length, added, removed);
|
|
276
273
|
}
|
|
277
274
|
async getRoleActions(roleId) {
|
|
@@ -303,94 +300,88 @@ let PermissionService = class PermissionService {
|
|
|
303
300
|
// Company-Action Permissions (Whitelist)
|
|
304
301
|
/** Assign or remove actions to/from a company (whitelist) */ async assignCompanyActions(dto) {
|
|
305
302
|
const permissionRepo = await this.getPermissionRepository();
|
|
306
|
-
const dataSource =
|
|
303
|
+
const dataSource = await this.dataSourceProvider.getDataSource();
|
|
304
|
+
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
307
305
|
const { toAdd: itemsToAdd, toRemove: itemsToRemove } = this.splitItemsByAction(dto.items);
|
|
308
306
|
let added = 0;
|
|
309
307
|
let removed = 0;
|
|
310
308
|
await dataSource.transaction(async (manager)=>{
|
|
311
309
|
const transactionalPermissionRepo = manager.getRepository(permissionRepo.target);
|
|
312
310
|
if (itemsToAdd.length > 0) {
|
|
313
|
-
|
|
311
|
+
const actionIdsToAdd = itemsToAdd.map((item)=>item.id);
|
|
312
|
+
const existingPermissions = await transactionalPermissionRepo.find({
|
|
313
|
+
where: {
|
|
314
|
+
permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION,
|
|
315
|
+
sourceType: _iamentitytypeenum.IamEntityType.COMPANY,
|
|
316
|
+
sourceId: dto.companyId,
|
|
317
|
+
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
318
|
+
targetId: (0, _typeorm.In)(actionIdsToAdd)
|
|
319
|
+
},
|
|
320
|
+
select: [
|
|
321
|
+
'targetId'
|
|
322
|
+
]
|
|
323
|
+
});
|
|
324
|
+
const existingActionIds = new Set(existingPermissions.map((p)=>p.targetId));
|
|
325
|
+
const newActionIds = actionIdsToAdd.filter((id)=>!existingActionIds.has(id));
|
|
326
|
+
if (newActionIds.length > 0) {
|
|
327
|
+
const newPermissions = newActionIds.map((actionId)=>transactionalPermissionRepo.create({
|
|
328
|
+
permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION,
|
|
329
|
+
sourceType: _iamentitytypeenum.IamEntityType.COMPANY,
|
|
330
|
+
sourceId: dto.companyId,
|
|
331
|
+
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
332
|
+
targetId: actionId
|
|
333
|
+
}));
|
|
334
|
+
await transactionalPermissionRepo.save(newPermissions);
|
|
335
|
+
added = newPermissions.length;
|
|
336
|
+
}
|
|
314
337
|
}
|
|
315
338
|
if (itemsToRemove.length > 0) {
|
|
316
339
|
const actionIdsToRemove = itemsToRemove.map((item)=>item.id);
|
|
317
|
-
|
|
340
|
+
const companyResult = await transactionalPermissionRepo.delete({
|
|
341
|
+
permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION,
|
|
342
|
+
sourceType: _iamentitytypeenum.IamEntityType.COMPANY,
|
|
343
|
+
sourceId: dto.companyId,
|
|
344
|
+
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
345
|
+
targetId: (0, _typeorm.In)(actionIdsToRemove)
|
|
346
|
+
});
|
|
347
|
+
removed = companyResult.affected || 0;
|
|
348
|
+
// Cascade: an action no longer on the company whitelist must not remain
|
|
349
|
+
// reachable via role grants or direct user grants scoped to this company.
|
|
350
|
+
const roleEntity = enableCompanyFeature ? _rolewithcompanyentity.RoleWithCompany : _roleentity.Role;
|
|
351
|
+
const roleRepo = manager.getRepository(roleEntity);
|
|
352
|
+
const companyRoles = await roleRepo.find({
|
|
353
|
+
where: {
|
|
354
|
+
companyId: dto.companyId,
|
|
355
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
356
|
+
},
|
|
357
|
+
select: [
|
|
358
|
+
'id'
|
|
359
|
+
]
|
|
360
|
+
});
|
|
361
|
+
if (companyRoles.length > 0) {
|
|
362
|
+
const roleIds = companyRoles.map((role)=>role.id);
|
|
363
|
+
await transactionalPermissionRepo.delete({
|
|
364
|
+
permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
|
|
365
|
+
sourceType: _iamentitytypeenum.IamEntityType.ROLE,
|
|
366
|
+
sourceId: (0, _typeorm.In)(roleIds),
|
|
367
|
+
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
368
|
+
targetId: (0, _typeorm.In)(actionIdsToRemove)
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
if (enableCompanyFeature) {
|
|
372
|
+
await transactionalPermissionRepo.delete({
|
|
373
|
+
permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
|
|
374
|
+
companyId: dto.companyId,
|
|
375
|
+
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
376
|
+
targetId: (0, _typeorm.In)(actionIdsToRemove)
|
|
377
|
+
});
|
|
378
|
+
}
|
|
318
379
|
}
|
|
319
380
|
});
|
|
320
|
-
await this.invalidateCompanyMembersCache(dto.companyId);
|
|
381
|
+
await this.permissionCacheService.invalidateCompanyMembersCache(dto.companyId);
|
|
321
382
|
return this.buildOperationResult(dto.items.length, added, removed);
|
|
322
383
|
}
|
|
323
|
-
async
|
|
324
|
-
const existingPermissions = await permissionRepo.find({
|
|
325
|
-
where: {
|
|
326
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION,
|
|
327
|
-
sourceType: _iamentitytypeenum.IamEntityType.COMPANY,
|
|
328
|
-
sourceId: companyId,
|
|
329
|
-
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
330
|
-
targetId: (0, _typeorm.In)(actionIds)
|
|
331
|
-
},
|
|
332
|
-
select: [
|
|
333
|
-
'targetId'
|
|
334
|
-
]
|
|
335
|
-
});
|
|
336
|
-
const existingActionIds = new Set(existingPermissions.map((p)=>p.targetId));
|
|
337
|
-
const newActionIds = actionIds.filter((id)=>!existingActionIds.has(id));
|
|
338
|
-
if (newActionIds.length === 0) {
|
|
339
|
-
return 0;
|
|
340
|
-
}
|
|
341
|
-
const newPermissions = newActionIds.map((actionId)=>permissionRepo.create({
|
|
342
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION,
|
|
343
|
-
sourceType: _iamentitytypeenum.IamEntityType.COMPANY,
|
|
344
|
-
sourceId: companyId,
|
|
345
|
-
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
346
|
-
targetId: actionId,
|
|
347
|
-
userId: null
|
|
348
|
-
}));
|
|
349
|
-
await permissionRepo.save(newPermissions);
|
|
350
|
-
return newPermissions.length;
|
|
351
|
-
}
|
|
352
|
-
async removeCompanyActionsWithCascade(manager, companyId, actionIds) {
|
|
353
|
-
const permissionEntity = this.iamConfigService.isCompanyFeatureEnabled() ? _permissionwithcompanyentity.UserIamPermissionWithCompany : _useriampermissionentity.UserIamPermission;
|
|
354
|
-
const permissionRepo = manager.getRepository(permissionEntity);
|
|
355
|
-
const companyResult = await permissionRepo.delete({
|
|
356
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION,
|
|
357
|
-
sourceType: _iamentitytypeenum.IamEntityType.COMPANY,
|
|
358
|
-
sourceId: companyId,
|
|
359
|
-
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
360
|
-
targetId: (0, _typeorm.In)(actionIds)
|
|
361
|
-
});
|
|
362
|
-
const roleEntity = this.iamConfigService.isCompanyFeatureEnabled() ? _rolewithcompanyentity.RoleWithCompany : _roleentity.Role;
|
|
363
|
-
const roleRepo = manager.getRepository(roleEntity);
|
|
364
|
-
const companyRoles = await roleRepo.find({
|
|
365
|
-
where: {
|
|
366
|
-
companyId,
|
|
367
|
-
deletedAt: (0, _typeorm.IsNull)()
|
|
368
|
-
},
|
|
369
|
-
select: [
|
|
370
|
-
'id'
|
|
371
|
-
]
|
|
372
|
-
});
|
|
373
|
-
if (companyRoles.length > 0) {
|
|
374
|
-
const roleIds = companyRoles.map((role)=>role.id);
|
|
375
|
-
await permissionRepo.delete({
|
|
376
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
|
|
377
|
-
sourceType: _iamentitytypeenum.IamEntityType.ROLE,
|
|
378
|
-
sourceId: (0, _typeorm.In)(roleIds),
|
|
379
|
-
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
380
|
-
targetId: (0, _typeorm.In)(actionIds)
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
if (this.iamConfigService.isCompanyFeatureEnabled()) {
|
|
384
|
-
await permissionRepo.delete({
|
|
385
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
|
|
386
|
-
companyId,
|
|
387
|
-
targetType: _iamentitytypeenum.IamEntityType.ACTION,
|
|
388
|
-
targetId: (0, _typeorm.In)(actionIds)
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
return companyResult.affected || 0;
|
|
392
|
-
}
|
|
393
|
-
/** Get all actions assigned to a company (whitelist) */ async getCompanyActions(companyId) {
|
|
384
|
+
/** Get all actions assigned to a company (whitelist) */ async getCompanyActions(companyId, isOnlyId = false) {
|
|
394
385
|
const permissionRepo = await this.getPermissionRepository();
|
|
395
386
|
const permissions = await permissionRepo.find({
|
|
396
387
|
where: {
|
|
@@ -403,6 +394,7 @@ let PermissionService = class PermissionService {
|
|
|
403
394
|
return [];
|
|
404
395
|
}
|
|
405
396
|
const actionIds = permissions.map((p)=>p.targetId);
|
|
397
|
+
if (isOnlyId) return actionIds;
|
|
406
398
|
const actionMap = await this.getActionsMap(actionIds);
|
|
407
399
|
return permissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
|
|
408
400
|
const action = actionMap.get(p.targetId);
|
|
@@ -416,20 +408,6 @@ let PermissionService = class PermissionService {
|
|
|
416
408
|
};
|
|
417
409
|
});
|
|
418
410
|
}
|
|
419
|
-
/** Get action IDs whitelisted for a company */ async getCompanyActionIds(companyId) {
|
|
420
|
-
const permissionRepo = await this.getPermissionRepository();
|
|
421
|
-
const permissions = await permissionRepo.find({
|
|
422
|
-
where: {
|
|
423
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION,
|
|
424
|
-
sourceType: _iamentitytypeenum.IamEntityType.COMPANY,
|
|
425
|
-
sourceId: companyId
|
|
426
|
-
},
|
|
427
|
-
select: [
|
|
428
|
-
'targetId'
|
|
429
|
-
]
|
|
430
|
-
});
|
|
431
|
-
return permissions.map((p)=>p.targetId);
|
|
432
|
-
}
|
|
433
411
|
// User-Role Permissions
|
|
434
412
|
/** Assign user to roles (branch-scoped when company feature is enabled) */ async assignUserRoles(dto) {
|
|
435
413
|
if (!this.iamConfigService.isRbacEnabled()) {
|
|
@@ -471,7 +449,6 @@ let PermissionService = class PermissionService {
|
|
|
471
449
|
sourceId: dto.userId,
|
|
472
450
|
targetType: _iamentitytypeenum.IamEntityType.ROLE,
|
|
473
451
|
targetId: item.id,
|
|
474
|
-
userId: dto.userId,
|
|
475
452
|
companyId: enableCompanyFeature ? companyId : null,
|
|
476
453
|
branchId: enableCompanyFeature ? branchId : null
|
|
477
454
|
}));
|
|
@@ -522,7 +499,7 @@ let PermissionService = class PermissionService {
|
|
|
522
499
|
};
|
|
523
500
|
if (enableCompanyFeature) {
|
|
524
501
|
if (companyId) where.companyId = companyId;
|
|
525
|
-
where.branchId = branchId
|
|
502
|
+
if (branchId) where.branchId = branchId;
|
|
526
503
|
}
|
|
527
504
|
const permissions = await permissionRepo.find({
|
|
528
505
|
where
|
|
@@ -546,7 +523,7 @@ let PermissionService = class PermissionService {
|
|
|
546
523
|
const permissionEntity = p;
|
|
547
524
|
return {
|
|
548
525
|
id: p.id,
|
|
549
|
-
userId: p.
|
|
526
|
+
userId: p.sourceId,
|
|
550
527
|
roleId: role.id,
|
|
551
528
|
roleName: role.name,
|
|
552
529
|
branchId: enableCompanyFeature ? permissionEntity.branchId ?? null : null,
|
|
@@ -556,129 +533,7 @@ let PermissionService = class PermissionService {
|
|
|
556
533
|
}
|
|
557
534
|
// My Permissions
|
|
558
535
|
/** Get user's effective permissions (cache-first approach) */ async getMyPermissions(userId, branchId, companyId, parentCodes) {
|
|
559
|
-
|
|
560
|
-
const cacheOptions = {
|
|
561
|
-
userId,
|
|
562
|
-
companyId: enableCompanyFeature ? companyId : null,
|
|
563
|
-
branchId
|
|
564
|
-
};
|
|
565
|
-
const cachedData = await this.permissionCacheService.getMyPermissions(cacheOptions);
|
|
566
|
-
if (cachedData) {
|
|
567
|
-
return this.buildResponseFromCache(cachedData, parentCodes);
|
|
568
|
-
}
|
|
569
|
-
const freshData = await this.fetchAndCachePermissions(userId, branchId, companyId);
|
|
570
|
-
return this.buildResponseFromCache(freshData, parentCodes);
|
|
571
|
-
}
|
|
572
|
-
/** Build response from cached data, applying optional parentCodes filter */ async buildResponseFromCache(cachedData, parentCodes) {
|
|
573
|
-
let frontendActions = cachedData.frontendActions;
|
|
574
|
-
if (parentCodes?.length) {
|
|
575
|
-
const parentIds = await this.getParentIdsByCodesWithCache(parentCodes);
|
|
576
|
-
if (parentIds.size > 0) {
|
|
577
|
-
frontendActions = frontendActions.filter((a)=>a.parentId && parentIds.has(a.parentId));
|
|
578
|
-
} else {
|
|
579
|
-
frontendActions = [];
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
return {
|
|
583
|
-
frontendActions: frontendActions.map((a)=>({
|
|
584
|
-
id: a.id,
|
|
585
|
-
code: a.code,
|
|
586
|
-
name: a.name,
|
|
587
|
-
description: a.description
|
|
588
|
-
})),
|
|
589
|
-
cachedEndpoints: cachedData.backendCodes.length
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
/** Resolve action IDs for the given codes */ async getParentIdsByCodesWithCache(codes) {
|
|
593
|
-
const actionRepo = await this.getActionRepository();
|
|
594
|
-
const actions = await actionRepo.find({
|
|
595
|
-
where: {
|
|
596
|
-
code: (0, _typeorm.In)(codes)
|
|
597
|
-
},
|
|
598
|
-
select: [
|
|
599
|
-
'id',
|
|
600
|
-
'code'
|
|
601
|
-
]
|
|
602
|
-
});
|
|
603
|
-
return new Set(actions.map((action)=>action.id));
|
|
604
|
-
}
|
|
605
|
-
/** Fetch permissions from DB and cache them (empty permissions are also cached) */ async fetchAndCachePermissions(userId, branchId, companyId) {
|
|
606
|
-
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
607
|
-
const cacheOptions = {
|
|
608
|
-
userId,
|
|
609
|
-
companyId: enableCompanyFeature ? companyId : null,
|
|
610
|
-
branchId
|
|
611
|
-
};
|
|
612
|
-
const emptyData = {
|
|
613
|
-
frontendActions: [],
|
|
614
|
-
backendCodes: []
|
|
615
|
-
};
|
|
616
|
-
const allActionIds = await this.collectAllActionIds(userId, branchId, companyId);
|
|
617
|
-
if (allActionIds.size === 0) {
|
|
618
|
-
await this.permissionCacheService.setMyPermissions(cacheOptions, emptyData);
|
|
619
|
-
return emptyData;
|
|
620
|
-
}
|
|
621
|
-
await this.applyCompanyWhitelist(allActionIds, companyId);
|
|
622
|
-
if (allActionIds.size === 0) {
|
|
623
|
-
await this.permissionCacheService.setMyPermissions(cacheOptions, emptyData);
|
|
624
|
-
return emptyData;
|
|
625
|
-
}
|
|
626
|
-
return this.buildAndCachePermissionData(allActionIds, cacheOptions);
|
|
627
|
-
}
|
|
628
|
-
/** Collect all action IDs based on permission mode (RBAC, DIRECT, or FULL) */ async collectAllActionIds(userId, branchId, companyId) {
|
|
629
|
-
const permissionMode = this.iamConfigService.getPermissionMode();
|
|
630
|
-
const allActionIds = new Set();
|
|
631
|
-
if (permissionMode === _permissiontypeenum.IAMPermissionMode.RBAC || permissionMode === _permissiontypeenum.IAMPermissionMode.FULL) {
|
|
632
|
-
const userRoleIds = await this.getUserRoleIds(userId, branchId, companyId);
|
|
633
|
-
if (userRoleIds.length > 0) {
|
|
634
|
-
const roleActionIds = await this.getRoleActionIds(userRoleIds);
|
|
635
|
-
roleActionIds.forEach((id)=>allActionIds.add(id));
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
if (permissionMode === _permissiontypeenum.IAMPermissionMode.DIRECT || permissionMode === _permissiontypeenum.IAMPermissionMode.FULL) {
|
|
639
|
-
const userActionIds = await this.getUserActionIds(userId, branchId, companyId);
|
|
640
|
-
userActionIds.forEach((id)=>allActionIds.add(id));
|
|
641
|
-
}
|
|
642
|
-
return allActionIds;
|
|
643
|
-
}
|
|
644
|
-
/** Apply company whitelist filter to action IDs (mutates the set) */ async applyCompanyWhitelist(actionIds, companyId) {
|
|
645
|
-
if (!this.iamConfigService.isCompanyFeatureEnabled() || !companyId) {
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
const companyActionIds = await this.getCompanyActionIds(companyId);
|
|
649
|
-
if (companyActionIds.length === 0) {
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
const allowedActionIds = new Set(companyActionIds);
|
|
653
|
-
for (const actionId of actionIds){
|
|
654
|
-
if (!allowedActionIds.has(actionId)) {
|
|
655
|
-
actionIds.delete(actionId);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
/** Fetch actions from DB, separate by type, build cache data, and cache it */ async buildAndCachePermissionData(actionIds, cacheOptions) {
|
|
660
|
-
const actionRepo = await this.getActionRepository();
|
|
661
|
-
const actions = await actionRepo.find({
|
|
662
|
-
where: {
|
|
663
|
-
id: (0, _typeorm.In)(Array.from(actionIds)),
|
|
664
|
-
isActive: true
|
|
665
|
-
}
|
|
666
|
-
});
|
|
667
|
-
const backendActions = actions.filter((a)=>a.actionType === _actiontypeenum.ActionType.BACKEND || a.actionType === _actiontypeenum.ActionType.BOTH);
|
|
668
|
-
const frontendActions = actions.filter((a)=>a.actionType === _actiontypeenum.ActionType.FRONTEND || a.actionType === _actiontypeenum.ActionType.BOTH);
|
|
669
|
-
const backendCodes = backendActions.map((a)=>a.code).filter((c)=>!!c);
|
|
670
|
-
const cacheData = {
|
|
671
|
-
frontendActions: frontendActions.map((a)=>({
|
|
672
|
-
id: a.id,
|
|
673
|
-
code: a.code ?? '',
|
|
674
|
-
name: a.name,
|
|
675
|
-
description: a.description,
|
|
676
|
-
parentId: a.parentId
|
|
677
|
-
})),
|
|
678
|
-
backendCodes
|
|
679
|
-
};
|
|
680
|
-
await this.permissionCacheService.setMyPermissions(cacheOptions, cacheData);
|
|
681
|
-
return cacheData;
|
|
536
|
+
return this.permissionCacheService.getMyPermissionsResponse(userId, branchId, companyId, parentCodes);
|
|
682
537
|
}
|
|
683
538
|
// Helper Methods
|
|
684
539
|
/** Split permission items into add and remove arrays */ splitItemsByAction(items) {
|
|
@@ -694,176 +549,13 @@ let PermissionService = class PermissionService {
|
|
|
694
549
|
total: _totalItems
|
|
695
550
|
};
|
|
696
551
|
}
|
|
697
|
-
/** Get role IDs assigned to a user (merges company-wide + branch-specific roles) */ async getUserRoleIds(userId, branchId, companyId) {
|
|
698
|
-
const permissionRepo = await this.getPermissionRepository();
|
|
699
|
-
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
700
|
-
if (!enableCompanyFeature) {
|
|
701
|
-
const permissions = await permissionRepo.find({
|
|
702
|
-
where: {
|
|
703
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
|
|
704
|
-
sourceType: _iamentitytypeenum.IamEntityType.USER,
|
|
705
|
-
sourceId: userId
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
|
|
709
|
-
}
|
|
710
|
-
const roleIds = new Set();
|
|
711
|
-
const baseWhere = {
|
|
712
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
|
|
713
|
-
sourceType: _iamentitytypeenum.IamEntityType.USER,
|
|
714
|
-
sourceId: userId
|
|
715
|
-
};
|
|
716
|
-
if (companyId) {
|
|
717
|
-
baseWhere.companyId = companyId;
|
|
718
|
-
}
|
|
719
|
-
if (branchId) {
|
|
720
|
-
// Get company-wide + branch-specific roles
|
|
721
|
-
const companyWidePermissions = await permissionRepo.find({
|
|
722
|
-
where: {
|
|
723
|
-
...baseWhere,
|
|
724
|
-
branchId: (0, _typeorm.IsNull)()
|
|
725
|
-
}
|
|
726
|
-
});
|
|
727
|
-
companyWidePermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
|
|
728
|
-
const branchPermissions = await permissionRepo.find({
|
|
729
|
-
where: {
|
|
730
|
-
...baseWhere,
|
|
731
|
-
branchId
|
|
732
|
-
}
|
|
733
|
-
});
|
|
734
|
-
branchPermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
|
|
735
|
-
} else {
|
|
736
|
-
// No branch context: get all roles for this company
|
|
737
|
-
const allPermissions = await permissionRepo.find({
|
|
738
|
-
where: baseWhere
|
|
739
|
-
});
|
|
740
|
-
allPermissions.filter((p)=>p.isValid()).forEach((p)=>roleIds.add(p.targetId));
|
|
741
|
-
}
|
|
742
|
-
return Array.from(roleIds);
|
|
743
|
-
}
|
|
744
|
-
async getRoleActionIds(roleIds) {
|
|
745
|
-
const permissionRepo = await this.getPermissionRepository();
|
|
746
|
-
const permissions = await permissionRepo.find({
|
|
747
|
-
where: {
|
|
748
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
|
|
749
|
-
sourceType: _iamentitytypeenum.IamEntityType.ROLE,
|
|
750
|
-
sourceId: (0, _typeorm.In)(roleIds)
|
|
751
|
-
}
|
|
752
|
-
});
|
|
753
|
-
return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
|
|
754
|
-
}
|
|
755
|
-
/** Get action IDs directly assigned to a user (merges company-wide + branch-specific actions) */ async getUserActionIds(userId, branchId, companyId) {
|
|
756
|
-
const permissionRepo = await this.getPermissionRepository();
|
|
757
|
-
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
758
|
-
if (!enableCompanyFeature) {
|
|
759
|
-
const permissions = await permissionRepo.find({
|
|
760
|
-
where: {
|
|
761
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
|
|
762
|
-
sourceType: _iamentitytypeenum.IamEntityType.USER,
|
|
763
|
-
sourceId: userId
|
|
764
|
-
}
|
|
765
|
-
});
|
|
766
|
-
return permissions.filter((p)=>p.isValid()).map((p)=>p.targetId);
|
|
767
|
-
}
|
|
768
|
-
const actionIds = new Set();
|
|
769
|
-
const baseWhere = {
|
|
770
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
|
|
771
|
-
sourceType: _iamentitytypeenum.IamEntityType.USER,
|
|
772
|
-
sourceId: userId
|
|
773
|
-
};
|
|
774
|
-
if (companyId) {
|
|
775
|
-
baseWhere.companyId = companyId;
|
|
776
|
-
}
|
|
777
|
-
if (branchId) {
|
|
778
|
-
// Get company-wide + branch-specific actions
|
|
779
|
-
const companyWidePermissions = await permissionRepo.find({
|
|
780
|
-
where: {
|
|
781
|
-
...baseWhere,
|
|
782
|
-
branchId: (0, _typeorm.IsNull)()
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
companyWidePermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
|
|
786
|
-
const branchPermissions = await permissionRepo.find({
|
|
787
|
-
where: {
|
|
788
|
-
...baseWhere,
|
|
789
|
-
branchId
|
|
790
|
-
}
|
|
791
|
-
});
|
|
792
|
-
branchPermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
|
|
793
|
-
} else {
|
|
794
|
-
// No branch context: get all actions for this company
|
|
795
|
-
const allPermissions = await permissionRepo.find({
|
|
796
|
-
where: baseWhere
|
|
797
|
-
});
|
|
798
|
-
allPermissions.filter((p)=>p.isValid()).forEach((p)=>actionIds.add(p.targetId));
|
|
799
|
-
}
|
|
800
|
-
return Array.from(actionIds);
|
|
801
|
-
}
|
|
802
|
-
async invalidateRoleMembersCache(roleId) {
|
|
803
|
-
const permissionRepo = await this.getPermissionRepository();
|
|
804
|
-
const roleRepo = await this.getRoleRepository();
|
|
805
|
-
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
806
|
-
const userRoles = await permissionRepo.find({
|
|
807
|
-
where: {
|
|
808
|
-
permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
|
|
809
|
-
sourceType: _iamentitytypeenum.IamEntityType.USER,
|
|
810
|
-
targetType: _iamentitytypeenum.IamEntityType.ROLE,
|
|
811
|
-
targetId: roleId
|
|
812
|
-
}
|
|
813
|
-
});
|
|
814
|
-
const userIds = [
|
|
815
|
-
...new Set(userRoles.map((ur)=>ur.sourceId))
|
|
816
|
-
];
|
|
817
|
-
if (userIds.length === 0) {
|
|
818
|
-
return 0;
|
|
819
|
-
}
|
|
820
|
-
const role = await roleRepo.findOne({
|
|
821
|
-
where: {
|
|
822
|
-
id: roleId
|
|
823
|
-
}
|
|
824
|
-
});
|
|
825
|
-
const companyId = role?.companyId || null;
|
|
826
|
-
let branchIds = [
|
|
827
|
-
null
|
|
828
|
-
];
|
|
829
|
-
if (enableCompanyFeature && companyId) {
|
|
830
|
-
const userBranches = await permissionRepo.createQueryBuilder('p').select('DISTINCT p.branch_id', 'branchId').where('p.user_id IN (:...userIds)', {
|
|
831
|
-
userIds
|
|
832
|
-
}).andWhere('p.company_id = :companyId', {
|
|
833
|
-
companyId
|
|
834
|
-
}).getRawMany();
|
|
835
|
-
branchIds = [
|
|
836
|
-
...new Set(userBranches.map((p)=>p.branchId))
|
|
837
|
-
];
|
|
838
|
-
}
|
|
839
|
-
return this.permissionCacheService.invalidateUsers(userIds, companyId, branchIds);
|
|
840
|
-
}
|
|
841
|
-
/** Invalidate permission cache for all users in a company */ async invalidateCompanyMembersCache(companyId) {
|
|
842
|
-
if (!this.iamConfigService.isCompanyFeatureEnabled()) {
|
|
843
|
-
return 0;
|
|
844
|
-
}
|
|
845
|
-
const permissionRepo = await this.getPermissionRepository();
|
|
846
|
-
const userPermissions = await permissionRepo.createQueryBuilder('p').select('DISTINCT p.user_id', 'userId').addSelect('p.branch_id', 'branchId').where('p.company_id = :companyId', {
|
|
847
|
-
companyId
|
|
848
|
-
}).andWhere('p.user_id IS NOT NULL').getRawMany();
|
|
849
|
-
const userIds = [
|
|
850
|
-
...new Set(userPermissions.map((p)=>p.userId).filter(Boolean))
|
|
851
|
-
];
|
|
852
|
-
const branchIds = [
|
|
853
|
-
...new Set(userPermissions.map((p)=>p.branchId))
|
|
854
|
-
]; // includes null
|
|
855
|
-
if (userIds.length === 0) {
|
|
856
|
-
return 0;
|
|
857
|
-
}
|
|
858
|
-
return await this.permissionCacheService.invalidateUsers(userIds, companyId, branchIds);
|
|
859
|
-
}
|
|
860
552
|
async revokeCompanyPermissions(companyId) {
|
|
861
553
|
if (!this.iamConfigService.isCompanyFeatureEnabled()) {
|
|
862
554
|
return;
|
|
863
555
|
}
|
|
864
556
|
const permissionRepo = await this.getPermissionRepository();
|
|
865
557
|
const roleRepo = await this.getRoleRepository();
|
|
866
|
-
const dataSource =
|
|
558
|
+
const dataSource = await this.dataSourceProvider.getDataSource();
|
|
867
559
|
const companyRoles = await roleRepo.find({
|
|
868
560
|
where: {
|
|
869
561
|
companyId,
|
|
@@ -880,14 +572,15 @@ let PermissionService = class PermissionService {
|
|
|
880
572
|
_iampermissiontypeenum.IamPermissionType.USER_ROLE,
|
|
881
573
|
_iampermissiontypeenum.IamPermissionType.USER_ACTION
|
|
882
574
|
]),
|
|
575
|
+
sourceType: _iamentitytypeenum.IamEntityType.USER,
|
|
883
576
|
companyId
|
|
884
577
|
},
|
|
885
578
|
select: [
|
|
886
|
-
'
|
|
579
|
+
'sourceId'
|
|
887
580
|
]
|
|
888
581
|
});
|
|
889
582
|
const affectedUserIds = [
|
|
890
|
-
...new Set(affectedUserRows.map((row)=>row.
|
|
583
|
+
...new Set(affectedUserRows.map((row)=>row.sourceId))
|
|
891
584
|
];
|
|
892
585
|
await dataSource.transaction(async (manager)=>{
|
|
893
586
|
const txRepo = manager.getRepository(permissionRepo.target);
|
|
@@ -929,17 +622,20 @@ let PermissionService = class PermissionService {
|
|
|
929
622
|
_iampermissiontypeenum.IamPermissionType.USER_ROLE,
|
|
930
623
|
_iampermissiontypeenum.IamPermissionType.USER_ACTION
|
|
931
624
|
]),
|
|
932
|
-
|
|
933
|
-
|
|
625
|
+
companyId,
|
|
626
|
+
branchId
|
|
934
627
|
};
|
|
935
628
|
const affectedUserRows = await permissionRepo.find({
|
|
936
|
-
where
|
|
629
|
+
where: {
|
|
630
|
+
...where,
|
|
631
|
+
sourceType: _iamentitytypeenum.IamEntityType.USER
|
|
632
|
+
},
|
|
937
633
|
select: [
|
|
938
|
-
'
|
|
634
|
+
'sourceId'
|
|
939
635
|
]
|
|
940
636
|
});
|
|
941
637
|
const affectedUserIds = [
|
|
942
|
-
...new Set(affectedUserRows.map((row)=>row.
|
|
638
|
+
...new Set(affectedUserRows.map((row)=>row.sourceId))
|
|
943
639
|
];
|
|
944
640
|
await permissionRepo.delete(where);
|
|
945
641
|
if (affectedUserIds.length > 0) {
|