@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.
Files changed (39) hide show
  1. package/cjs/controllers/company-action-permission.controller.js +1 -1
  2. package/cjs/controllers/company-action-permission.controller.spec.js +1 -1
  3. package/cjs/controllers/user-action-permission.controller.js +1 -1
  4. package/cjs/controllers/user-action-permission.controller.spec.js +1 -1
  5. package/cjs/dtos/permission.dto.js +7 -0
  6. package/cjs/entities/permission-base.entity.js +1 -10
  7. package/cjs/entities/permission-with-company.entity.js +0 -3
  8. package/cjs/entities/user-iam-permission.entity.js +0 -3
  9. package/cjs/modules/iam.module.js +2 -2
  10. package/cjs/services/action.service.js +4 -4
  11. package/cjs/services/action.service.spec.js +11 -11
  12. package/cjs/services/permission-cache.service.js +363 -52
  13. package/cjs/services/permission-cache.service.spec.js +462 -15
  14. package/cjs/services/permission.service.js +92 -396
  15. package/cjs/services/permission.service.spec.js +35 -310
  16. package/cjs/services/role.service.js +1 -1
  17. package/cjs/services/role.service.spec.js +4 -7
  18. package/dtos/permission.dto.d.ts +1 -0
  19. package/entities/permission-base.entity.d.ts +0 -1
  20. package/fesm/controllers/company-action-permission.controller.js +1 -1
  21. package/fesm/controllers/company-action-permission.controller.spec.js +1 -1
  22. package/fesm/controllers/user-action-permission.controller.js +1 -1
  23. package/fesm/controllers/user-action-permission.controller.spec.js +1 -1
  24. package/fesm/dtos/permission.dto.js +7 -0
  25. package/fesm/entities/permission-base.entity.js +1 -10
  26. package/fesm/entities/permission-with-company.entity.js +0 -3
  27. package/fesm/entities/user-iam-permission.entity.js +0 -3
  28. package/fesm/modules/iam.module.js +4 -4
  29. package/fesm/services/action.service.js +4 -4
  30. package/fesm/services/action.service.spec.js +11 -11
  31. package/fesm/services/permission-cache.service.js +365 -51
  32. package/fesm/services/permission-cache.service.spec.js +462 -15
  33. package/fesm/services/permission.service.js +92 -396
  34. package/fesm/services/permission.service.spec.js +35 -310
  35. package/fesm/services/role.service.js +1 -1
  36. package/fesm/services/role.service.spec.js +4 -7
  37. package/package.json +3 -3
  38. package/services/permission-cache.service.d.ts +20 -3
  39. package/services/permission.service.d.ts +2 -16
@@ -25,7 +25,6 @@ function buildPermissionRow(overrides = {}) {
25
25
  sourceId: 'user-1',
26
26
  targetType: _iamentitytypeenum.IamEntityType.ACTION,
27
27
  targetId: 'action-1',
28
- userId: 'user-1',
29
28
  companyId: null,
30
29
  branchId: null,
31
30
  validFrom: null,
@@ -99,8 +98,9 @@ describe('PermissionService', ()=>{
99
98
  mockPermissionCacheService = {
100
99
  invalidateUser: jest.fn(),
101
100
  invalidateUsers: jest.fn(),
102
- getMyPermissions: jest.fn(),
103
- setMyPermissions: jest.fn()
101
+ invalidateRoleMembersCache: jest.fn(),
102
+ invalidateCompanyMembersCache: jest.fn(),
103
+ getMyPermissionsResponse: jest.fn()
104
104
  };
105
105
  const module = await _testing.Test.createTestingModule({
106
106
  providers: [
@@ -172,9 +172,7 @@ describe('PermissionService', ()=>{
172
172
  removed: 1,
173
173
  total: 3
174
174
  });
175
- expect(mockPermissionCacheService.invalidateUser).toHaveBeenCalledWith('user-1', null, [
176
- null
177
- ]);
175
+ expect(mockPermissionCacheService.invalidateUser).toHaveBeenCalledWith('user-1', null, []);
178
176
  });
179
177
  it('scopes new permissions and cache invalidation to the company/branch when the company feature is enabled', async ()=>{
180
178
  mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
@@ -245,7 +243,7 @@ describe('PermissionService', ()=>{
245
243
  describe('getUserActions', ()=>{
246
244
  it('returns an empty array without querying actions when the user has no permissions', async ()=>{
247
245
  mockPermissionRepo.find.mockResolvedValue([]);
248
- const result = await service.getUserActions('user-1', undefined);
246
+ const result = await service.getUserActions('user-1', undefined, undefined);
249
247
  expect(result).toEqual([]);
250
248
  expect(mockActionRepo.find).not.toHaveBeenCalled();
251
249
  });
@@ -264,7 +262,7 @@ describe('PermissionService', ()=>{
264
262
  id: 'action-1'
265
263
  })
266
264
  ]);
267
- const result = await service.getUserActions('user-1', undefined);
265
+ const result = await service.getUserActions('user-1', undefined, undefined);
268
266
  expect(result).toHaveLength(1);
269
267
  expect(result[0]).toEqual(expect.objectContaining({
270
268
  actionId: 'action-1',
@@ -274,7 +272,7 @@ describe('PermissionService', ()=>{
274
272
  it('filters by companyId/branchId when the company feature is enabled', async ()=>{
275
273
  mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
276
274
  mockPermissionRepo.find.mockResolvedValue([]);
277
- await service.getUserActions('user-1', 'branch-1', 'company-1');
275
+ await service.getUserActions('user-1', 'company-1', 'branch-1');
278
276
  expect(mockPermissionRepo.find).toHaveBeenCalledWith({
279
277
  where: expect.objectContaining({
280
278
  companyId: 'company-1',
@@ -336,31 +334,18 @@ describe('PermissionService', ()=>{
336
334
  });
337
335
  });
338
336
  it('removes role actions and reports counts and invalidates role member caches', async ()=>{
339
- mockPermissionRepo.find.mockResolvedValueOnce([]) // existing check for add
340
- .mockResolvedValueOnce([
341
- buildPermissionRow({
342
- sourceId: 'user-9'
343
- })
344
- ]); // invalidateRoleMembersCache lookup (sourceId = the user who holds the role)
337
+ mockPermissionRepo.find.mockResolvedValue([]); // existing check for add
345
338
  mockPermissionRepo.save.mockResolvedValue([
346
339
  {}
347
340
  ]);
348
341
  mockPermissionRepo.delete.mockResolvedValue(buildDeleteResult(1));
349
- mockRoleRepo.findOne.mockResolvedValue({
350
- id: 'role-1',
351
- companyId: null
352
- });
353
342
  const result = await service.assignRoleActions(dto);
354
343
  expect(result).toEqual({
355
344
  added: 1,
356
345
  removed: 1,
357
346
  total: 2
358
347
  });
359
- expect(mockPermissionCacheService.invalidateUsers).toHaveBeenCalledWith([
360
- 'user-9'
361
- ], null, [
362
- null
363
- ]);
348
+ expect(mockPermissionCacheService.invalidateRoleMembersCache).toHaveBeenCalledWith('role-1');
364
349
  });
365
350
  });
366
351
  describe('getRoleActions', ()=>{
@@ -399,7 +384,9 @@ describe('PermissionService', ()=>{
399
384
  return mockPermissionRepo;
400
385
  })
401
386
  };
402
- mockPermissionRepo.manager.connection.transaction = jest.fn().mockImplementation((cb)=>cb(fakeManager));
387
+ mockDataSourceProvider.getDataSource.mockResolvedValue({
388
+ transaction: jest.fn().mockImplementation((cb)=>cb(fakeManager))
389
+ });
403
390
  return fakeManager;
404
391
  }
405
392
  it('adds new company-whitelisted actions inside a transaction, skipping duplicates', async ()=>{
@@ -433,7 +420,7 @@ describe('PermissionService', ()=>{
433
420
  })
434
421
  ]);
435
422
  expect(result.added).toBe(1);
436
- expect(mockPermissionCacheService.invalidateUsers).not.toHaveBeenCalled(); // no company feature -> invalidateCompanyMembersCache no-ops
423
+ expect(mockPermissionCacheService.invalidateCompanyMembersCache).toHaveBeenCalledWith('company-1');
437
424
  });
438
425
  it('cascades removal to role-action and user-action permissions for the company', async ()=>{
439
426
  mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
@@ -501,7 +488,7 @@ describe('PermissionService', ()=>{
501
488
  targetId: 'action-2'
502
489
  }
503
490
  ]);
504
- const result = await service.getCompanyActionIds('company-1');
491
+ const result = await service.getCompanyActions('company-1', true);
505
492
  expect(result).toEqual([
506
493
  'action-1',
507
494
  'action-2'
@@ -588,287 +575,26 @@ describe('PermissionService', ()=>{
588
575
  });
589
576
  // ==================== My Permissions / permission-mode branching ====================
590
577
  describe('getMyPermissions', ()=>{
591
- it('returns the response built directly from cached data on a cache hit', async ()=>{
592
- mockPermissionCacheService.getMyPermissions.mockResolvedValue({
578
+ it('delegates to the cache service and returns its response', async ()=>{
579
+ const response = {
593
580
  frontendActions: [
594
581
  {
595
582
  id: 'action-1',
596
583
  code: 'user.view',
597
584
  name: 'View',
598
- description: null,
599
- parentId: null
600
- }
601
- ],
602
- backendCodes: [
603
- 'user.read'
604
- ]
605
- });
606
- const result = await service.getMyPermissions('user-1', null, 'company-1');
607
- expect(result.frontendActions).toHaveLength(1);
608
- expect(result.cachedEndpoints).toBe(1);
609
- expect(mockPermissionRepo.find).not.toHaveBeenCalled();
610
- });
611
- it('fetches from the database and caches the result on a cache miss', async ()=>{
612
- mockPermissionCacheService.getMyPermissions.mockResolvedValue(null);
613
- mockPermissionRepo.find.mockResolvedValue([]);
614
- const result = await service.getMyPermissions('user-1', null, null);
615
- expect(result).toEqual({
616
- frontendActions: [],
617
- cachedEndpoints: 0
618
- });
619
- expect(mockPermissionCacheService.setMyPermissions).toHaveBeenCalled();
620
- });
621
- it('filters frontend actions by parentCodes when provided', async ()=>{
622
- mockPermissionCacheService.getMyPermissions.mockResolvedValue({
623
- frontendActions: [
624
- {
625
- id: 'child-1',
626
- code: 'user.view',
627
- name: 'View',
628
- description: null,
629
- parentId: 'parent-1'
630
- },
631
- {
632
- id: 'child-2',
633
- code: 'other.view',
634
- name: 'View 2',
635
- description: null,
636
- parentId: 'other-parent'
585
+ description: null
637
586
  }
638
587
  ],
639
- backendCodes: []
640
- });
641
- mockActionRepo.find.mockResolvedValue([
642
- {
643
- id: 'parent-1',
644
- code: 'user'
645
- }
646
- ]);
647
- const result = await service.getMyPermissions('user-1', null, null, [
648
- 'user'
649
- ]);
650
- expect(result.frontendActions).toHaveLength(1);
651
- expect(result.frontendActions[0].id).toBe('child-1');
652
- });
653
- it('returns an empty frontendActions list when parentCodes resolve to no known parents', async ()=>{
654
- mockPermissionCacheService.getMyPermissions.mockResolvedValue({
655
- frontendActions: [
656
- {
657
- id: 'child-1',
658
- code: 'user.view',
659
- name: 'View',
660
- description: null,
661
- parentId: 'parent-1'
662
- }
663
- ],
664
- backendCodes: []
665
- });
666
- mockActionRepo.find.mockResolvedValue([]);
667
- const result = await service.getMyPermissions('user-1', null, null, [
668
- 'unknown-parent-code'
669
- ]);
670
- expect(result.frontendActions).toEqual([]);
671
- });
672
- });
673
- describe('collectAllActionIds (permission-mode branching)', ()=>{
674
- it('RBAC mode: collects only role-derived action ids, ignoring direct user actions', async ()=>{
675
- mockIamConfigService.getPermissionMode.mockReturnValue(_permissiontypeenum.IAMPermissionMode.RBAC);
676
- mockPermissionRepo.find.mockImplementation(async ({ where })=>{
677
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.USER_ROLE) {
678
- return [
679
- buildPermissionRow({
680
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
681
- targetId: 'role-1'
682
- })
683
- ];
684
- }
685
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.ROLE_ACTION) {
686
- return [
687
- buildPermissionRow({
688
- permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
689
- targetId: 'action-role-1'
690
- })
691
- ];
692
- }
693
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.USER_ACTION) {
694
- throw new Error('DIRECT lookup should not run in RBAC mode');
695
- }
696
- return [];
697
- });
698
- const result = await service.collectAllActionIds('user-1', null, null);
699
- expect(Array.from(result)).toEqual([
700
- 'action-role-1'
701
- ]);
702
- });
703
- it('DIRECT mode: collects only directly-assigned user action ids, ignoring roles', async ()=>{
704
- mockIamConfigService.getPermissionMode.mockReturnValue(_permissiontypeenum.IAMPermissionMode.DIRECT);
705
- mockPermissionRepo.find.mockImplementation(async ({ where })=>{
706
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.USER_ROLE) {
707
- throw new Error('RBAC lookup should not run in DIRECT mode');
708
- }
709
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.USER_ACTION) {
710
- return [
711
- buildPermissionRow({
712
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
713
- targetId: 'action-direct-1'
714
- })
715
- ];
716
- }
717
- return [];
718
- });
719
- const result = await service.collectAllActionIds('user-1', null, null);
720
- expect(Array.from(result)).toEqual([
721
- 'action-direct-1'
722
- ]);
723
- });
724
- it('FULL mode: merges role-derived and direct action ids, de-duplicating overlaps', async ()=>{
725
- mockIamConfigService.getPermissionMode.mockReturnValue(_permissiontypeenum.IAMPermissionMode.FULL);
726
- mockPermissionRepo.find.mockImplementation(async ({ where })=>{
727
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.USER_ROLE) {
728
- return [
729
- buildPermissionRow({
730
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ROLE,
731
- targetId: 'role-1'
732
- })
733
- ];
734
- }
735
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.ROLE_ACTION) {
736
- return [
737
- buildPermissionRow({
738
- permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
739
- targetId: 'action-shared'
740
- })
741
- ];
742
- }
743
- if (where.permissionType === _iampermissiontypeenum.IamPermissionType.USER_ACTION) {
744
- return [
745
- buildPermissionRow({
746
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
747
- targetId: 'action-shared'
748
- }),
749
- buildPermissionRow({
750
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
751
- targetId: 'action-direct-only'
752
- })
753
- ];
754
- }
755
- return [];
756
- });
757
- const result = await service.collectAllActionIds('user-1', null, null);
758
- expect(Array.from(result).sort()).toEqual([
759
- 'action-direct-only',
760
- 'action-shared'
761
- ]);
762
- });
763
- it('excludes expired/not-yet-valid permission rows via isValid()', async ()=>{
764
- mockIamConfigService.getPermissionMode.mockReturnValue(_permissiontypeenum.IAMPermissionMode.DIRECT);
765
- const expired = buildPermissionRow({
766
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
767
- targetId: 'action-expired',
768
- validUntil: new Date('2000-01-01')
769
- });
770
- const active = buildPermissionRow({
771
- permissionType: _iampermissiontypeenum.IamPermissionType.USER_ACTION,
772
- targetId: 'action-active'
773
- });
774
- mockPermissionRepo.find.mockResolvedValue([
775
- expired,
776
- active
777
- ]);
778
- const result = await service.collectAllActionIds('user-1', null, null);
779
- expect(Array.from(result)).toEqual([
780
- 'action-active'
781
- ]);
782
- });
783
- });
784
- describe('applyCompanyWhitelist', ()=>{
785
- it('is a no-op when the company feature is disabled', async ()=>{
786
- const actionIds = new Set([
787
- 'action-1',
788
- 'action-2'
789
- ]);
790
- await service.applyCompanyWhitelist(actionIds, 'company-1');
791
- expect(actionIds).toEqual(new Set([
792
- 'action-1',
793
- 'action-2'
794
- ]));
795
- expect(mockPermissionRepo.find).not.toHaveBeenCalled();
796
- });
797
- it('is a no-op when companyId is missing even if the company feature is enabled', async ()=>{
798
- mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
799
- const actionIds = new Set([
800
- 'action-1'
801
- ]);
802
- await service.applyCompanyWhitelist(actionIds, null);
803
- expect(actionIds).toEqual(new Set([
804
- 'action-1'
805
- ]));
806
- });
807
- it('does not filter anything when the company has an empty whitelist', async ()=>{
808
- mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
809
- mockPermissionRepo.find.mockResolvedValue([]);
810
- const actionIds = new Set([
811
- 'action-1',
812
- 'action-2'
813
- ]);
814
- await service.applyCompanyWhitelist(actionIds, 'company-1');
815
- expect(actionIds).toEqual(new Set([
816
- 'action-1',
817
- 'action-2'
818
- ]));
819
- });
820
- it('removes action ids that are not present in the company whitelist', async ()=>{
821
- mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
822
- mockPermissionRepo.find.mockResolvedValue([
823
- {
824
- targetId: 'action-1'
825
- }
826
- ]);
827
- const actionIds = new Set([
828
- 'action-1',
829
- 'action-2'
830
- ]);
831
- await service.applyCompanyWhitelist(actionIds, 'company-1');
832
- expect(actionIds).toEqual(new Set([
833
- 'action-1'
834
- ]));
835
- });
836
- });
837
- // ==================== Cache invalidation helpers ====================
838
- describe('invalidateCompanyMembersCache', ()=>{
839
- it('returns 0 without querying when the company feature is disabled', async ()=>{
840
- const result = await service.invalidateCompanyMembersCache('company-1');
841
- expect(result).toBe(0);
842
- expect(mockPermissionRepo.createQueryBuilder).not.toHaveBeenCalled();
843
- });
844
- it('returns 0 when the company has no members with permissions', async ()=>{
845
- mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
846
- mockRawMany(mockPermissionRepo, []);
847
- const result = await service.invalidateCompanyMembersCache('company-1');
848
- expect(result).toBe(0);
849
- });
850
- it('invalidates every distinct member user id for the company', async ()=>{
851
- mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
852
- mockRawMany(mockPermissionRepo, [
853
- {
854
- userId: 'user-1',
855
- branchId: 'branch-1'
856
- },
857
- {
858
- userId: 'user-2',
859
- branchId: null
860
- }
588
+ cachedEndpoints: 1
589
+ };
590
+ mockPermissionCacheService.getMyPermissionsResponse.mockResolvedValue(response);
591
+ const result = await service.getMyPermissions('user-1', null, 'company-1', [
592
+ 'parent-code'
861
593
  ]);
862
- mockPermissionCacheService.invalidateUsers.mockResolvedValue(2);
863
- const result = await service.invalidateCompanyMembersCache('company-1');
864
- expect(mockPermissionCacheService.invalidateUsers).toHaveBeenCalledWith([
865
- 'user-1',
866
- 'user-2'
867
- ], 'company-1', [
868
- 'branch-1',
869
- null
594
+ expect(mockPermissionCacheService.getMyPermissionsResponse).toHaveBeenCalledWith('user-1', null, 'company-1', [
595
+ 'parent-code'
870
596
  ]);
871
- expect(result).toBe(2);
597
+ expect(result).toBe(response);
872
598
  });
873
599
  });
874
600
  describe('revokeCompanyPermissions', ()=>{
@@ -886,10 +612,7 @@ describe('PermissionService', ()=>{
886
612
  ]);
887
613
  mockPermissionRepo.find.mockResolvedValue([
888
614
  {
889
- userId: 'user-1'
890
- },
891
- {
892
- userId: null
615
+ sourceId: 'user-1'
893
616
  }
894
617
  ]);
895
618
  const fakeTxRepo = {
@@ -898,12 +621,14 @@ describe('PermissionService', ()=>{
898
621
  const fakeTxRoleRepo = {
899
622
  delete: jest.fn().mockResolvedValue(buildDeleteResult(1))
900
623
  };
901
- mockPermissionRepo.manager.connection.transaction = jest.fn().mockImplementation((cb)=>cb({
902
- getRepository: jest.fn((target)=>{
903
- if (target === mockRoleRepo.target) return fakeTxRoleRepo;
904
- return fakeTxRepo;
905
- })
906
- }));
624
+ mockDataSourceProvider.getDataSource.mockResolvedValue({
625
+ transaction: jest.fn().mockImplementation((cb)=>cb({
626
+ getRepository: jest.fn((target)=>{
627
+ if (target === mockRoleRepo.target) return fakeTxRoleRepo;
628
+ return fakeTxRepo;
629
+ })
630
+ }))
631
+ });
907
632
  await service.revokeCompanyPermissions('company-1');
908
633
  expect(fakeTxRepo.delete).toHaveBeenCalledWith(expect.objectContaining({
909
634
  permissionType: _iampermissiontypeenum.IamPermissionType.COMPANY_ACTION
@@ -925,7 +650,7 @@ describe('PermissionService', ()=>{
925
650
  mockIamConfigService.isCompanyFeatureEnabled.mockReturnValue(true);
926
651
  mockPermissionRepo.find.mockResolvedValue([
927
652
  {
928
- userId: 'user-1'
653
+ sourceId: 'user-1'
929
654
  }
930
655
  ]);
931
656
  mockPermissionRepo.delete.mockResolvedValue(buildDeleteResult(1));
@@ -70,7 +70,7 @@ let RoleService = class RoleService extends _classes.ApiService {
70
70
  }
71
71
  });
72
72
  const affectedUserIds = [
73
- ...new Set(userRoleRows.map((row)=>row.userId).filter((id)=>!!id))
73
+ ...new Set(userRoleRows.map((row)=>row.sourceId))
74
74
  ];
75
75
  await permissionRepo.delete({
76
76
  permissionType: _iampermissiontypeenum.IamPermissionType.ROLE_ACTION,
@@ -247,13 +247,10 @@ describe('RoleService', ()=>{
247
247
  const permissionRepo = (0, _repositorymock.createMockRepository)();
248
248
  permissionRepo.find.mockResolvedValue([
249
249
  {
250
- userId: 'user-1'
250
+ sourceId: 'user-1'
251
251
  },
252
252
  {
253
- userId: 'user-2'
254
- },
255
- {
256
- userId: null
253
+ sourceId: 'user-2'
257
254
  }
258
255
  ]);
259
256
  const queryRunner = buildQueryRunner(permissionRepo);
@@ -290,10 +287,10 @@ describe('RoleService', ()=>{
290
287
  const permissionRepo = (0, _repositorymock.createMockRepository)();
291
288
  permissionRepo.find.mockResolvedValue([
292
289
  {
293
- userId: 'user-1'
290
+ sourceId: 'user-1'
294
291
  },
295
292
  {
296
- userId: 'user-1'
293
+ sourceId: 'user-1'
297
294
  }
298
295
  ]);
299
296
  const queryRunner = buildQueryRunner(permissionRepo);
@@ -48,6 +48,7 @@ export declare class UserActionResponseDto {
48
48
  actionId: string;
49
49
  actionCode: string;
50
50
  actionName: string;
51
+ companyId: string | null;
51
52
  branchId: string | null;
52
53
  createdAt: Date;
53
54
  }
@@ -5,7 +5,6 @@ export declare abstract class PermissionBase extends Identity {
5
5
  sourceId: string;
6
6
  targetType: string;
7
7
  targetId: string;
8
- userId: string | null;
9
8
  validFrom: Date | null;
10
9
  validUntil: Date | null;
11
10
  reason: string | null;
@@ -47,7 +47,7 @@ export class CompanyActionPermissionController {
47
47
  };
48
48
  }
49
49
  async getCompanyActions(dto) {
50
- const actions = await this.permissionService.getCompanyActions(dto.companyId);
50
+ const actions = await this.permissionService.getCompanyActions(dto.companyId, false);
51
51
  return {
52
52
  success: true,
53
53
  message: 'Company actions retrieved successfully',
@@ -50,7 +50,7 @@ describe('CompanyActionPermissionController', ()=>{
50
50
  const result = await controller.getCompanyActions({
51
51
  companyId: 'company-1'
52
52
  });
53
- expect(mockPermissionService.getCompanyActions).toHaveBeenCalledWith('company-1');
53
+ expect(mockPermissionService.getCompanyActions).toHaveBeenCalledWith('company-1', false);
54
54
  expect(result.data).toEqual([
55
55
  {
56
56
  actionId: 'action-1'
@@ -48,7 +48,7 @@ export class UserActionPermissionController {
48
48
  };
49
49
  }
50
50
  async getUserActions(dto, user) {
51
- const actions = await this.permissionService.getUserActions(dto.userId, dto.branchId, dto.companyId);
51
+ const actions = await this.permissionService.getUserActions(dto.userId, dto.companyId, dto.branchId);
52
52
  return {
53
53
  success: true,
54
54
  message: 'User actions retrieved successfully',
@@ -53,7 +53,7 @@ describe('UserActionPermissionController', ()=>{
53
53
  branchId: 'branch-1',
54
54
  companyId: 'company-1'
55
55
  }, user);
56
- expect(mockPermissionService.getUserActions).toHaveBeenCalledWith('user-2', 'branch-1', 'company-1');
56
+ expect(mockPermissionService.getUserActions).toHaveBeenCalledWith('user-2', 'company-1', 'branch-1');
57
57
  expect(result.data).toEqual([
58
58
  {
59
59
  actionId: 'action-1'
@@ -285,6 +285,7 @@ export class UserActionResponseDto {
285
285
  _define_property(this, "actionId", void 0);
286
286
  _define_property(this, "actionCode", void 0);
287
287
  _define_property(this, "actionName", void 0);
288
+ _define_property(this, "companyId", void 0);
288
289
  _define_property(this, "branchId", void 0);
289
290
  _define_property(this, "createdAt", void 0);
290
291
  }
@@ -319,6 +320,12 @@ _ts_decorate([
319
320
  }),
320
321
  _ts_metadata("design:type", String)
321
322
  ], UserActionResponseDto.prototype, "actionName", void 0);
323
+ _ts_decorate([
324
+ ApiPropertyOptional({
325
+ description: 'Company ID (null = global)'
326
+ }),
327
+ _ts_metadata("design:type", Object)
328
+ ], UserActionResponseDto.prototype, "companyId", void 0);
322
329
  _ts_decorate([
323
330
  ApiPropertyOptional({
324
331
  description: 'Branch ID (null = company-wide)'
@@ -32,7 +32,7 @@ import { Column } from 'typeorm';
32
32
  return true;
33
33
  }
34
34
  constructor(...args){
35
- super(...args), _define_property(this, "permissionType", void 0), _define_property(this, "sourceType", void 0), _define_property(this, "sourceId", void 0), _define_property(this, "targetType", void 0), _define_property(this, "targetId", void 0), _define_property(this, "userId", void 0), _define_property(this, "validFrom", void 0), _define_property(this, "validUntil", void 0), _define_property(this, "reason", void 0);
35
+ super(...args), _define_property(this, "permissionType", void 0), _define_property(this, "sourceType", void 0), _define_property(this, "sourceId", void 0), _define_property(this, "targetType", void 0), _define_property(this, "targetId", void 0), _define_property(this, "validFrom", void 0), _define_property(this, "validUntil", void 0), _define_property(this, "reason", void 0);
36
36
  }
37
37
  }
38
38
  _ts_decorate([
@@ -75,15 +75,6 @@ _ts_decorate([
75
75
  }),
76
76
  _ts_metadata("design:type", String)
77
77
  ], PermissionBase.prototype, "targetId", void 0);
78
- _ts_decorate([
79
- Column({
80
- type: 'varchar',
81
- length: 150,
82
- nullable: true,
83
- name: 'user_id'
84
- }),
85
- _ts_metadata("design:type", Object)
86
- ], PermissionBase.prototype, "userId", void 0);
87
78
  _ts_decorate([
88
79
  Column({
89
80
  type: 'timestamp',
@@ -77,9 +77,6 @@ UserIamPermissionWithCompany = _ts_decorate([
77
77
  Index([
78
78
  'permissionType'
79
79
  ]),
80
- Index([
81
- 'userId'
82
- ]),
83
80
  Index([
84
81
  'companyId'
85
82
  ]),
@@ -29,8 +29,5 @@ UserIamPermission = _ts_decorate([
29
29
  ]),
30
30
  Index([
31
31
  'permissionType'
32
- ]),
33
- Index([
34
- 'userId'
35
32
  ])
36
33
  ], UserIamPermission);
@@ -4,7 +4,7 @@ function _ts_decorate(decorators, target, key, desc) {
4
4
  else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  }
7
- import { PERMISSION_GUARD_CONFIG } from '@flusys/nestjs-shared';
7
+ import { PERMISSION_GUARD_CONFIG, PERMISSIONS_CACHE_PREFIX } from '@flusys/nestjs-shared';
8
8
  import { CacheModule, UtilsModule } from '@flusys/nestjs-shared/modules';
9
9
  import { Module } from '@nestjs/common';
10
10
  import { IAM_MODULE_OPTIONS } from '../config/iam.constants';
@@ -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 { MY_PERMISSIONS_CACHE_PREFIX, PermissionCacheService } from '../services/permission-cache.service';
17
+ import { PermissionCacheService } from '../services/permission-cache.service';
18
18
  export class IAMModule {
19
19
  static getControllers(permissionMode, enableCompanyFeature) {
20
20
  const baseControllers = [
@@ -59,8 +59,8 @@ export class IAMModule {
59
59
  provide: PERMISSION_GUARD_CONFIG,
60
60
  useValue: {
61
61
  enableCompanyFeature,
62
- userPermissionKeyFormat: `${MY_PERMISSIONS_CACHE_PREFIX}:user:{userId}`,
63
- companyPermissionKeyFormat: `${MY_PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`
62
+ userPermissionKeyFormat: `${PERMISSIONS_CACHE_PREFIX}:user:{userId}`,
63
+ companyPermissionKeyFormat: `${PERMISSIONS_CACHE_PREFIX}:company:{companyId}:branch:{branchId}:user:{userId}`
64
64
  }
65
65
  };
66
66
  }