@flusys/nestjs-iam 7.0.2 → 8.0.0-beta.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 (173) hide show
  1. package/config/index.d.ts +3 -3
  2. package/controllers/action.controller.d.ts +4 -4
  3. package/controllers/company-action-permission.controller.d.ts +2 -2
  4. package/controllers/index.d.ts +6 -6
  5. package/controllers/my-permission.controller.d.ts +3 -3
  6. package/controllers/role-permission.controller.d.ts +4 -4
  7. package/controllers/role.controller.d.ts +2 -2
  8. package/controllers/user-action-permission.controller.d.ts +4 -4
  9. package/docs/iam-swagger.config.d.ts +2 -2
  10. package/docs/index.d.ts +1 -1
  11. package/dtos/action.dto.d.ts +2 -2
  12. package/dtos/index.d.ts +3 -3
  13. package/entities/action.entity.d.ts +2 -2
  14. package/entities/index.d.ts +11 -11
  15. package/entities/permission-with-company.entity.d.ts +1 -1
  16. package/entities/role-with-company.entity.d.ts +1 -1
  17. package/entities/role.entity.d.ts +1 -1
  18. package/entities/user-iam-permission.entity.d.ts +1 -1
  19. package/enums/index.d.ts +4 -4
  20. package/fesm/284.js +1262 -0
  21. package/fesm/867.js +3699 -0
  22. package/fesm/chunks/364.js +86 -0
  23. package/fesm/config/index.js +133 -3
  24. package/fesm/controllers/index.js +18 -7
  25. package/fesm/docs/index.js +240 -1
  26. package/fesm/dtos/index.js +1090 -3
  27. package/fesm/entities/index.js +670 -31
  28. package/fesm/enums/index.js +97 -4
  29. package/fesm/helpers/index.js +125 -2
  30. package/fesm/index.js +806 -11
  31. package/fesm/interfaces/index.js +17 -3
  32. package/fesm/modules/index.js +259 -1
  33. package/fesm/runtime.js +134 -0
  34. package/fesm/services/index.js +43 -6
  35. package/fesm/types/index.js +15 -1
  36. package/helpers/company-access.helper.d.ts +2 -2
  37. package/helpers/index.d.ts +2 -2
  38. package/helpers/permission-mode.helper.d.ts +1 -1
  39. package/index.d.ts +11 -11
  40. package/interfaces/action.interface.d.ts +2 -2
  41. package/interfaces/iam-module-options.interface.d.ts +3 -3
  42. package/interfaces/index.d.ts +3 -3
  43. package/modules/iam.module.d.ts +2 -2
  44. package/modules/index.d.ts +1 -1
  45. package/package.json +30 -37
  46. package/services/action.service.d.ts +9 -9
  47. package/services/iam-config.service.d.ts +4 -4
  48. package/services/iam-datasource.service.d.ts +3 -3
  49. package/services/index.d.ts +6 -6
  50. package/services/permission-cache.service.d.ts +5 -5
  51. package/services/permission.service.d.ts +4 -4
  52. package/services/role.service.d.ts +8 -8
  53. package/types/index.d.ts +1 -1
  54. package/cjs/config/event-actions.js +0 -36
  55. package/cjs/config/iam.constants.js +0 -11
  56. package/cjs/config/index.js +0 -20
  57. package/cjs/config/message-keys.js +0 -71
  58. package/cjs/controllers/action.controller.js +0 -174
  59. package/cjs/controllers/action.controller.spec.js +0 -79
  60. package/cjs/controllers/company-action-permission.controller.js +0 -119
  61. package/cjs/controllers/company-action-permission.controller.spec.js +0 -65
  62. package/cjs/controllers/index.js +0 -23
  63. package/cjs/controllers/my-permission.controller.js +0 -147
  64. package/cjs/controllers/my-permission.controller.spec.js +0 -128
  65. package/cjs/controllers/role-permission.controller.js +0 -191
  66. package/cjs/controllers/role-permission.controller.spec.js +0 -140
  67. package/cjs/controllers/role.controller.js +0 -102
  68. package/cjs/controllers/role.controller.spec.js +0 -86
  69. package/cjs/controllers/user-action-permission.controller.js +0 -129
  70. package/cjs/controllers/user-action-permission.controller.spec.js +0 -68
  71. package/cjs/docs/iam-swagger.config.js +0 -209
  72. package/cjs/docs/iam-swagger.config.spec.js +0 -99
  73. package/cjs/docs/index.js +0 -18
  74. package/cjs/dtos/action.dto.js +0 -282
  75. package/cjs/dtos/index.js +0 -21
  76. package/cjs/dtos/permission.dto.js +0 -637
  77. package/cjs/dtos/role.dto.js +0 -155
  78. package/cjs/entities/action.entity.js +0 -138
  79. package/cjs/entities/index.js +0 -80
  80. package/cjs/entities/index.spec.js +0 -56
  81. package/cjs/entities/permission-base.entity.js +0 -107
  82. package/cjs/entities/permission-with-company.entity.js +0 -100
  83. package/cjs/entities/role-base.entity.js +0 -80
  84. package/cjs/entities/role-with-company.entity.js +0 -55
  85. package/cjs/entities/role.entity.js +0 -25
  86. package/cjs/entities/user-iam-permission.entity.js +0 -43
  87. package/cjs/enums/action-type.enum.js +0 -22
  88. package/cjs/enums/iam-entity-type.enum.js +0 -17
  89. package/cjs/enums/iam-permission-type.enum.js +0 -17
  90. package/cjs/enums/index.js +0 -21
  91. package/cjs/enums/permission-type.enum.js +0 -16
  92. package/cjs/helpers/company-access.helper.js +0 -23
  93. package/cjs/helpers/company-access.helper.spec.js +0 -68
  94. package/cjs/helpers/index.js +0 -19
  95. package/cjs/helpers/permission-mode.helper.js +0 -49
  96. package/cjs/helpers/permission-mode.helper.spec.js +0 -54
  97. package/cjs/index.js +0 -28
  98. package/cjs/interfaces/action.interface.js +0 -4
  99. package/cjs/interfaces/iam-module-options.interface.js +0 -4
  100. package/cjs/interfaces/index.js +0 -20
  101. package/cjs/interfaces/role.interface.js +0 -7
  102. package/cjs/modules/iam.module.js +0 -186
  103. package/cjs/modules/iam.module.spec.js +0 -282
  104. package/cjs/modules/index.js +0 -18
  105. package/cjs/services/action.service.js +0 -337
  106. package/cjs/services/action.service.spec.js +0 -351
  107. package/cjs/services/iam-config.service.js +0 -87
  108. package/cjs/services/iam-config.service.spec.js +0 -110
  109. package/cjs/services/iam-datasource.service.js +0 -129
  110. package/cjs/services/iam-datasource.service.spec.js +0 -110
  111. package/cjs/services/index.js +0 -23
  112. package/cjs/services/permission-cache.service.js +0 -544
  113. package/cjs/services/permission-cache.service.spec.js +0 -718
  114. package/cjs/services/permission.service.js +0 -914
  115. package/cjs/services/permission.service.spec.js +0 -918
  116. package/cjs/services/role.service.js +0 -224
  117. package/cjs/services/role.service.spec.js +0 -347
  118. package/cjs/types/index.js +0 -18
  119. package/cjs/types/logic-node.type.js +0 -30
  120. package/fesm/config/event-actions.js +0 -15
  121. package/fesm/config/iam.constants.js +0 -1
  122. package/fesm/config/message-keys.js +0 -35
  123. package/fesm/controllers/action.controller.js +0 -164
  124. package/fesm/controllers/action.controller.spec.js +0 -75
  125. package/fesm/controllers/company-action-permission.controller.js +0 -109
  126. package/fesm/controllers/company-action-permission.controller.spec.js +0 -61
  127. package/fesm/controllers/my-permission.controller.js +0 -137
  128. package/fesm/controllers/my-permission.controller.spec.js +0 -124
  129. package/fesm/controllers/role-permission.controller.js +0 -181
  130. package/fesm/controllers/role-permission.controller.spec.js +0 -136
  131. package/fesm/controllers/role.controller.js +0 -92
  132. package/fesm/controllers/role.controller.spec.js +0 -82
  133. package/fesm/controllers/user-action-permission.controller.js +0 -119
  134. package/fesm/controllers/user-action-permission.controller.spec.js +0 -64
  135. package/fesm/docs/iam-swagger.config.js +0 -199
  136. package/fesm/docs/iam-swagger.config.spec.js +0 -95
  137. package/fesm/dtos/action.dto.js +0 -252
  138. package/fesm/dtos/permission.dto.js +0 -571
  139. package/fesm/dtos/role.dto.js +0 -134
  140. package/fesm/entities/action.entity.js +0 -128
  141. package/fesm/entities/index.spec.js +0 -52
  142. package/fesm/entities/permission-base.entity.js +0 -100
  143. package/fesm/entities/permission-with-company.entity.js +0 -90
  144. package/fesm/entities/role-base.entity.js +0 -70
  145. package/fesm/entities/role-with-company.entity.js +0 -45
  146. package/fesm/entities/role.entity.js +0 -15
  147. package/fesm/entities/user-iam-permission.entity.js +0 -33
  148. package/fesm/enums/action-type.enum.js +0 -12
  149. package/fesm/enums/iam-entity-type.enum.js +0 -7
  150. package/fesm/enums/iam-permission-type.enum.js +0 -7
  151. package/fesm/enums/permission-type.enum.js +0 -6
  152. package/fesm/helpers/company-access.helper.js +0 -18
  153. package/fesm/helpers/company-access.helper.spec.js +0 -64
  154. package/fesm/helpers/permission-mode.helper.js +0 -49
  155. package/fesm/helpers/permission-mode.helper.spec.js +0 -50
  156. package/fesm/interfaces/action.interface.js +0 -3
  157. package/fesm/interfaces/iam-module-options.interface.js +0 -3
  158. package/fesm/interfaces/role.interface.js +0 -4
  159. package/fesm/modules/iam.module.js +0 -176
  160. package/fesm/modules/iam.module.spec.js +0 -278
  161. package/fesm/services/action.service.js +0 -327
  162. package/fesm/services/action.service.spec.js +0 -347
  163. package/fesm/services/iam-config.service.js +0 -77
  164. package/fesm/services/iam-config.service.spec.js +0 -106
  165. package/fesm/services/iam-datasource.service.js +0 -78
  166. package/fesm/services/iam-datasource.service.spec.js +0 -106
  167. package/fesm/services/permission-cache.service.js +0 -527
  168. package/fesm/services/permission-cache.service.spec.js +0 -714
  169. package/fesm/services/permission.service.js +0 -904
  170. package/fesm/services/permission.service.spec.js +0 -914
  171. package/fesm/services/role.service.js +0 -214
  172. package/fesm/services/role.service.spec.js +0 -343
  173. package/fesm/types/logic-node.type.js +0 -27
@@ -1,904 +0,0 @@
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
- function _ts_decorate(decorators, target, key, desc) {
15
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
- 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;
18
- return c > 3 && r && Object.defineProperty(target, key, r), r;
19
- }
20
- function _ts_metadata(k, v) {
21
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
- }
23
- function _ts_param(paramIndex, decorator) {
24
- return function(target, key) {
25
- decorator(target, key, paramIndex);
26
- };
27
- }
28
- import { LogAction } from '@flusys/nestjs-shared';
29
- import { publishDomainEvent } from '@flusys/nestjs-shared/classes';
30
- import { BadRequestException, ConflictException, Inject, Injectable, Scope } from '@nestjs/common';
31
- import { In, IsNull } from 'typeorm';
32
- import { IAM_EVENT_ACTIONS, IAM_EVENT_ENTITIES, IAM_EVENT_MODULE, IAM_MODE_MESSAGES, PERMISSION_OPERATION_MESSAGES } from '../config';
33
- import { AssignCompanyActionsDto, AssignRoleActionsDto, AssignUserActionsDto, AssignUserRolesDto, PermissionAction } from '../dtos/permission.dto';
34
- import { Action } from '../entities/action.entity';
35
- import { UserIamPermissionWithCompany } from '../entities/permission-with-company.entity';
36
- import { RoleWithCompany } from '../entities/role-with-company.entity';
37
- import { Role } from '../entities/role.entity';
38
- import { UserIamPermission } from '../entities/user-iam-permission.entity';
39
- import { IamEntityType } from '../enums/iam-entity-type.enum';
40
- import { IamPermissionType } from '../enums/iam-permission-type.enum';
41
- import { IAMConfigService } from './iam-config.service';
42
- import { IAMDataSourceService } from './iam-datasource.service';
43
- import { PermissionCacheService } from './permission-cache.service';
44
- export class PermissionService {
45
- // Repository Getters
46
- async getPermissionRepository() {
47
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
48
- const entity = enableCompanyFeature ? UserIamPermissionWithCompany : UserIamPermission;
49
- return this.dataSourceProvider.getRepository(entity);
50
- }
51
- async getActionRepository() {
52
- return this.dataSourceProvider.getRepository(Action);
53
- }
54
- async getRoleRepository() {
55
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
56
- const entity = enableCompanyFeature ? RoleWithCompany : Role;
57
- return this.dataSourceProvider.getRepository(entity);
58
- }
59
- async getActionsMap(actionIds) {
60
- const actionRepo = await this.getActionRepository();
61
- const actions = await actionRepo.find({
62
- where: {
63
- id: In(actionIds)
64
- }
65
- });
66
- return new Map(actions.map((a)=>[
67
- a.id,
68
- a
69
- ]));
70
- }
71
- // User-Action Permissions
72
- async assignUserActions(dto) {
73
- if (!this.iamConfigService.isDirectPermissionEnabled()) {
74
- throw new BadRequestException({
75
- message: 'Direct permission assignment not available in RBAC-only mode. Use role-based permissions instead.',
76
- messageKey: IAM_MODE_MESSAGES.DIRECT_MODE_UNAVAILABLE
77
- });
78
- }
79
- const permissionRepo = await this.getPermissionRepository();
80
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
81
- const branchId = dto.branchId ?? null;
82
- const companyId = dto.companyId ?? null;
83
- const { toAdd: itemsToAdd, toRemove: itemsToRemove } = this.splitItemsByAction(dto.items);
84
- let added = 0;
85
- let removed = 0;
86
- if (itemsToAdd.length > 0) {
87
- const actionIdsToAdd = itemsToAdd.map((item)=>item.id);
88
- const whereFind = {
89
- permissionType: IamPermissionType.USER_ACTION,
90
- sourceType: IamEntityType.USER,
91
- sourceId: dto.userId,
92
- targetType: IamEntityType.ACTION,
93
- targetId: In(actionIdsToAdd)
94
- };
95
- if (enableCompanyFeature) {
96
- if (companyId) whereFind.companyId = companyId;
97
- if (branchId) whereFind.branchId = branchId;
98
- }
99
- const existingPermissions = await permissionRepo.find({
100
- where: whereFind,
101
- select: [
102
- 'targetId'
103
- ]
104
- });
105
- const existingActionIds = new Set(existingPermissions.map((p)=>p.targetId));
106
- const newPermissions = itemsToAdd.filter((item)=>!existingActionIds.has(item.id)).map((item)=>({
107
- permissionType: IamPermissionType.USER_ACTION,
108
- sourceType: IamEntityType.USER,
109
- sourceId: dto.userId,
110
- targetType: IamEntityType.ACTION,
111
- targetId: item.id,
112
- companyId: enableCompanyFeature ? companyId : null,
113
- branchId: enableCompanyFeature ? branchId : null
114
- }));
115
- if (newPermissions.length > 0) {
116
- try {
117
- await permissionRepo.save(newPermissions);
118
- added = newPermissions.length;
119
- } catch (error) {
120
- if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
121
- throw new ConflictException({
122
- message: 'Some permissions already exist for this user. Please refresh and try again.',
123
- messageKey: PERMISSION_OPERATION_MESSAGES.ALREADY_EXISTS
124
- });
125
- }
126
- throw error;
127
- }
128
- }
129
- }
130
- if (itemsToRemove.length > 0) {
131
- const actionIdsToRemove = itemsToRemove.map((item)=>item.id);
132
- const whereDelete = {
133
- permissionType: IamPermissionType.USER_ACTION,
134
- sourceType: IamEntityType.USER,
135
- sourceId: dto.userId,
136
- targetType: IamEntityType.ACTION,
137
- targetId: In(actionIdsToRemove)
138
- };
139
- if (enableCompanyFeature) {
140
- if (companyId) whereDelete.companyId = companyId;
141
- if (branchId) whereDelete.branchId = branchId;
142
- }
143
- const result = await permissionRepo.delete(whereDelete);
144
- removed = result.affected || 0;
145
- }
146
- await this.permissionCacheService.invalidateUser(dto.userId, enableCompanyFeature ? companyId : null, enableCompanyFeature ? [
147
- branchId
148
- ] : []);
149
- const result = this.buildOperationResult(dto.items.length, added, removed);
150
- await this.publishAssignmentEvent(IAM_EVENT_ENTITIES.USER_ACTION, dto.userId, result);
151
- return result;
152
- }
153
- async getUserActions(userId, companyId, branchId) {
154
- const permissionRepo = await this.getPermissionRepository();
155
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
156
- const where = {
157
- permissionType: IamPermissionType.USER_ACTION,
158
- sourceType: IamEntityType.USER,
159
- sourceId: userId
160
- };
161
- if (enableCompanyFeature) {
162
- if (companyId) where.companyId = companyId;
163
- if (branchId) where.branchId = branchId;
164
- }
165
- const permissions = await permissionRepo.find({
166
- where
167
- });
168
- if (permissions.length === 0) {
169
- return [];
170
- }
171
- const actionIds = permissions.map((p)=>p.targetId);
172
- const actionMap = await this.getActionsMap(actionIds);
173
- return permissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
174
- const action = actionMap.get(p.targetId);
175
- return {
176
- id: p.id,
177
- userId: p.sourceId,
178
- actionId: action.id,
179
- actionCode: action.code ?? '',
180
- actionName: action.name,
181
- companyId: ('companyId' in p ? p.companyId : null) ?? null,
182
- branchId: ('branchId' in p ? p.branchId : null) ?? null,
183
- createdAt: p.createdAt
184
- };
185
- });
186
- }
187
- // Role-Action Permissions
188
- async assignRoleActions(dto) {
189
- if (!this.iamConfigService.isRbacEnabled()) {
190
- throw new BadRequestException({
191
- message: 'Role-based permission assignment not available in DIRECT-only mode. Use direct user permissions instead.',
192
- messageKey: IAM_MODE_MESSAGES.RBAC_MODE_UNAVAILABLE
193
- });
194
- }
195
- const permissionRepo = await this.getPermissionRepository();
196
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
197
- let roleCompanyId = null;
198
- if (enableCompanyFeature) {
199
- const roleRepo = await this.getRoleRepository();
200
- const role = await roleRepo.findOne({
201
- where: {
202
- id: dto.roleId
203
- },
204
- select: [
205
- 'id',
206
- 'companyId'
207
- ]
208
- });
209
- roleCompanyId = role?.companyId ?? null;
210
- }
211
- const { toAdd: itemsToAdd, toRemove: itemsToRemove } = this.splitItemsByAction(dto.items);
212
- let added = 0;
213
- let removed = 0;
214
- if (itemsToAdd.length > 0) {
215
- const actionIdsToAdd = itemsToAdd.map((item)=>item.id);
216
- const existingPermissions = await permissionRepo.find({
217
- where: {
218
- permissionType: IamPermissionType.ROLE_ACTION,
219
- sourceType: IamEntityType.ROLE,
220
- sourceId: dto.roleId,
221
- targetType: IamEntityType.ACTION,
222
- targetId: In(actionIdsToAdd)
223
- },
224
- select: [
225
- 'targetId'
226
- ]
227
- });
228
- const existingActionIds = new Set(existingPermissions.map((p)=>p.targetId));
229
- const newPermissions = itemsToAdd.filter((item)=>!existingActionIds.has(item.id)).map((item)=>({
230
- permissionType: IamPermissionType.ROLE_ACTION,
231
- sourceType: IamEntityType.ROLE,
232
- sourceId: dto.roleId,
233
- targetType: IamEntityType.ACTION,
234
- targetId: item.id,
235
- companyId: enableCompanyFeature ? roleCompanyId : null,
236
- branchId: null
237
- }));
238
- if (newPermissions.length > 0) {
239
- try {
240
- await permissionRepo.save(newPermissions);
241
- added = newPermissions.length;
242
- } catch (error) {
243
- if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
244
- throw new ConflictException({
245
- message: 'Some role-action permissions already exist. Please refresh and try again.',
246
- messageKey: PERMISSION_OPERATION_MESSAGES.ALREADY_EXISTS
247
- });
248
- }
249
- throw error;
250
- }
251
- }
252
- }
253
- if (itemsToRemove.length > 0) {
254
- const actionIdsToRemove = itemsToRemove.map((item)=>item.id);
255
- const result = await permissionRepo.delete({
256
- permissionType: IamPermissionType.ROLE_ACTION,
257
- sourceType: IamEntityType.ROLE,
258
- sourceId: dto.roleId,
259
- targetType: IamEntityType.ACTION,
260
- targetId: In(actionIdsToRemove)
261
- });
262
- removed = result.affected || 0;
263
- }
264
- await this.permissionCacheService.invalidateRoleMembersCache(dto.roleId);
265
- const result = this.buildOperationResult(dto.items.length, added, removed);
266
- await this.publishAssignmentEvent(IAM_EVENT_ENTITIES.ROLE_ACTION, dto.roleId, result);
267
- return result;
268
- }
269
- async getRoleActions(roleId) {
270
- const permissionRepo = await this.getPermissionRepository();
271
- const permissions = await permissionRepo.find({
272
- where: {
273
- permissionType: IamPermissionType.ROLE_ACTION,
274
- sourceType: IamEntityType.ROLE,
275
- sourceId: roleId
276
- }
277
- });
278
- if (permissions.length === 0) {
279
- return [];
280
- }
281
- const actionIds = permissions.map((p)=>p.targetId);
282
- const actionMap = await this.getActionsMap(actionIds);
283
- return permissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
284
- const action = actionMap.get(p.targetId);
285
- return {
286
- id: p.id,
287
- roleId: p.sourceId,
288
- actionId: action.id,
289
- actionCode: action.code ?? '',
290
- actionName: action.name,
291
- createdAt: p.createdAt
292
- };
293
- });
294
- }
295
- // Company-Action Permissions (Whitelist)
296
- /** Assign or remove actions to/from a company (whitelist) */ async assignCompanyActions(dto) {
297
- const permissionRepo = await this.getPermissionRepository();
298
- const dataSource = await this.dataSourceProvider.getDataSource();
299
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
300
- const { toAdd: itemsToAdd, toRemove: itemsToRemove } = this.splitItemsByAction(dto.items);
301
- let added = 0;
302
- let removed = 0;
303
- await dataSource.transaction(async (manager)=>{
304
- const transactionalPermissionRepo = manager.getRepository(permissionRepo.target);
305
- if (itemsToAdd.length > 0) {
306
- const actionIdsToAdd = itemsToAdd.map((item)=>item.id);
307
- const existingPermissions = await transactionalPermissionRepo.find({
308
- where: {
309
- permissionType: IamPermissionType.COMPANY_ACTION,
310
- sourceType: IamEntityType.COMPANY,
311
- sourceId: dto.companyId,
312
- targetType: IamEntityType.ACTION,
313
- targetId: In(actionIdsToAdd)
314
- },
315
- select: [
316
- 'targetId'
317
- ]
318
- });
319
- const existingActionIds = new Set(existingPermissions.map((p)=>p.targetId));
320
- const newActionIds = actionIdsToAdd.filter((id)=>!existingActionIds.has(id));
321
- if (newActionIds.length > 0) {
322
- const newPermissions = newActionIds.map((actionId)=>transactionalPermissionRepo.create({
323
- permissionType: IamPermissionType.COMPANY_ACTION,
324
- sourceType: IamEntityType.COMPANY,
325
- sourceId: dto.companyId,
326
- targetType: IamEntityType.ACTION,
327
- targetId: actionId
328
- }));
329
- await transactionalPermissionRepo.save(newPermissions);
330
- added = newPermissions.length;
331
- }
332
- }
333
- if (itemsToRemove.length > 0) {
334
- const actionIdsToRemove = itemsToRemove.map((item)=>item.id);
335
- const companyResult = await transactionalPermissionRepo.delete({
336
- permissionType: IamPermissionType.COMPANY_ACTION,
337
- sourceType: IamEntityType.COMPANY,
338
- sourceId: dto.companyId,
339
- targetType: IamEntityType.ACTION,
340
- targetId: In(actionIdsToRemove)
341
- });
342
- removed = companyResult.affected || 0;
343
- // Cascade: an action no longer on the company whitelist must not remain
344
- // reachable via role grants or direct user grants scoped to this company.
345
- const roleEntity = enableCompanyFeature ? RoleWithCompany : Role;
346
- const roleRepo = manager.getRepository(roleEntity);
347
- const companyRoles = await roleRepo.find({
348
- where: {
349
- companyId: dto.companyId,
350
- deletedAt: IsNull()
351
- },
352
- select: [
353
- 'id'
354
- ]
355
- });
356
- if (companyRoles.length > 0) {
357
- const roleIds = companyRoles.map((role)=>role.id);
358
- await transactionalPermissionRepo.delete({
359
- permissionType: IamPermissionType.ROLE_ACTION,
360
- sourceType: IamEntityType.ROLE,
361
- sourceId: In(roleIds),
362
- targetType: IamEntityType.ACTION,
363
- targetId: In(actionIdsToRemove)
364
- });
365
- }
366
- if (enableCompanyFeature) {
367
- await transactionalPermissionRepo.delete({
368
- permissionType: IamPermissionType.USER_ACTION,
369
- companyId: dto.companyId,
370
- targetType: IamEntityType.ACTION,
371
- targetId: In(actionIdsToRemove)
372
- });
373
- }
374
- }
375
- });
376
- await this.permissionCacheService.invalidateCompanyMembersCache(dto.companyId);
377
- const result = this.buildOperationResult(dto.items.length, added, removed);
378
- await this.publishAssignmentEvent(IAM_EVENT_ENTITIES.COMPANY_ACTION, dto.companyId, result);
379
- return result;
380
- }
381
- /** Get all actions assigned to a company (whitelist) */ async getCompanyActions(companyId, isOnlyId = false) {
382
- const permissionRepo = await this.getPermissionRepository();
383
- const permissions = await permissionRepo.find({
384
- where: {
385
- permissionType: IamPermissionType.COMPANY_ACTION,
386
- sourceType: IamEntityType.COMPANY,
387
- sourceId: companyId
388
- }
389
- });
390
- if (permissions.length === 0) {
391
- return [];
392
- }
393
- const actionIds = permissions.map((p)=>p.targetId);
394
- if (isOnlyId) return actionIds;
395
- const actionMap = await this.getActionsMap(actionIds);
396
- return permissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
397
- const action = actionMap.get(p.targetId);
398
- return {
399
- id: p.id,
400
- companyId: companyId,
401
- actionId: action.id,
402
- actionCode: action.code ?? '',
403
- actionName: action.name,
404
- createdAt: p.createdAt
405
- };
406
- });
407
- }
408
- // User-Role Permissions
409
- /** Assign user to roles (branch-scoped when company feature is enabled) */ async assignUserRoles(dto) {
410
- if (!this.iamConfigService.isRbacEnabled()) {
411
- throw new BadRequestException({
412
- message: 'Role assignment not available in DIRECT-only mode. Use direct user permissions instead.',
413
- messageKey: IAM_MODE_MESSAGES.ROLE_ASSIGNMENT_UNAVAILABLE
414
- });
415
- }
416
- const permissionRepo = await this.getPermissionRepository();
417
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
418
- const branchId = dto.branchId ?? null;
419
- const companyId = dto.companyId ?? null;
420
- const { toAdd: itemsToAdd, toRemove: itemsToRemove } = this.splitItemsByAction(dto.items);
421
- let added = 0;
422
- let removed = 0;
423
- if (itemsToAdd.length > 0) {
424
- const roleIdsToAdd = itemsToAdd.map((item)=>item.id);
425
- const whereFind = {
426
- permissionType: IamPermissionType.USER_ROLE,
427
- sourceType: IamEntityType.USER,
428
- sourceId: dto.userId,
429
- targetType: IamEntityType.ROLE,
430
- targetId: In(roleIdsToAdd)
431
- };
432
- if (enableCompanyFeature) {
433
- if (companyId) whereFind.companyId = companyId;
434
- if (branchId) whereFind.branchId = branchId;
435
- }
436
- const existingPermissions = await permissionRepo.find({
437
- where: whereFind,
438
- select: [
439
- 'targetId'
440
- ]
441
- });
442
- const existingRoleIds = new Set(existingPermissions.map((p)=>p.targetId));
443
- const newPermissions = itemsToAdd.filter((item)=>!existingRoleIds.has(item.id)).map((item)=>({
444
- permissionType: IamPermissionType.USER_ROLE,
445
- sourceType: IamEntityType.USER,
446
- sourceId: dto.userId,
447
- targetType: IamEntityType.ROLE,
448
- targetId: item.id,
449
- companyId: enableCompanyFeature ? companyId : null,
450
- branchId: enableCompanyFeature ? branchId : null
451
- }));
452
- if (newPermissions.length > 0) {
453
- try {
454
- await permissionRepo.save(newPermissions);
455
- added = newPermissions.length;
456
- } catch (error) {
457
- if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
458
- throw new ConflictException({
459
- message: 'Some user-role permissions already exist. Please refresh and try again.',
460
- messageKey: PERMISSION_OPERATION_MESSAGES.ALREADY_EXISTS
461
- });
462
- }
463
- throw error;
464
- }
465
- }
466
- }
467
- if (itemsToRemove.length > 0) {
468
- const roleIdsToRemove = itemsToRemove.map((item)=>item.id);
469
- const whereDelete = {
470
- permissionType: IamPermissionType.USER_ROLE,
471
- sourceType: IamEntityType.USER,
472
- sourceId: dto.userId,
473
- targetType: IamEntityType.ROLE,
474
- targetId: In(roleIdsToRemove)
475
- };
476
- if (enableCompanyFeature) {
477
- if (companyId) whereDelete.companyId = companyId;
478
- if (branchId) whereDelete.branchId = branchId;
479
- }
480
- const result = await permissionRepo.delete(whereDelete);
481
- removed = result.affected || 0;
482
- }
483
- await this.permissionCacheService.invalidateUser(dto.userId, enableCompanyFeature ? companyId : null, [
484
- branchId
485
- ]);
486
- const result = this.buildOperationResult(dto.items.length, added, removed);
487
- await this.publishAssignmentEvent(IAM_EVENT_ENTITIES.USER_ROLE, dto.userId, result);
488
- return result;
489
- }
490
- /** Get user's roles (branch-scoped, filtered by companyId and branchId if provided) */ async getUserRoles(userId, branchId, companyId) {
491
- const permissionRepo = await this.getPermissionRepository();
492
- const roleRepo = await this.getRoleRepository();
493
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
494
- const where = {
495
- permissionType: IamPermissionType.USER_ROLE,
496
- sourceType: IamEntityType.USER,
497
- sourceId: userId
498
- };
499
- if (enableCompanyFeature) {
500
- if (companyId) where.companyId = companyId;
501
- if (branchId) where.branchId = branchId;
502
- }
503
- const permissions = await permissionRepo.find({
504
- where
505
- });
506
- if (permissions.length === 0) {
507
- return [];
508
- }
509
- const roleIds = permissions.map((p)=>p.targetId);
510
- const roleWhere = {
511
- id: In(roleIds)
512
- };
513
- const roles = await roleRepo.find({
514
- where: roleWhere
515
- });
516
- const roleMap = new Map(roles.map((r)=>[
517
- r.id,
518
- r
519
- ]));
520
- return permissions.filter((p)=>roleMap.has(p.targetId)).map((p)=>{
521
- const role = roleMap.get(p.targetId);
522
- const permissionEntity = p;
523
- return {
524
- id: p.id,
525
- userId: p.sourceId,
526
- roleId: role.id,
527
- roleName: role.name,
528
- branchId: enableCompanyFeature ? permissionEntity.branchId ?? null : null,
529
- createdAt: p.createdAt
530
- };
531
- });
532
- }
533
- // Effective (Merged) Permissions — self-scoped, company-wide + branch-specific
534
- /** Get user's effective roles: company-wide (branchId null) merged with branch-specific */ async getUserEffectiveRoles(userId, companyId, branchId) {
535
- const permissionRepo = await this.getPermissionRepository();
536
- const roleRepo = await this.getRoleRepository();
537
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
538
- const baseWhere = {
539
- permissionType: IamPermissionType.USER_ROLE,
540
- sourceType: IamEntityType.USER,
541
- sourceId: userId
542
- };
543
- if (enableCompanyFeature && companyId) baseWhere.companyId = companyId;
544
- const permissions = enableCompanyFeature && branchId ? await permissionRepo.find({
545
- where: [
546
- {
547
- ...baseWhere,
548
- branchId: IsNull()
549
- },
550
- {
551
- ...baseWhere,
552
- branchId
553
- }
554
- ]
555
- }) : await permissionRepo.find({
556
- where: baseWhere
557
- });
558
- const validPermissions = permissions.filter((p)=>p.isValid());
559
- if (validPermissions.length === 0) {
560
- return [];
561
- }
562
- const roleIds = [
563
- ...new Set(validPermissions.map((p)=>p.targetId))
564
- ];
565
- const roles = await roleRepo.find({
566
- where: {
567
- id: In(roleIds)
568
- }
569
- });
570
- const roleMap = new Map(roles.map((r)=>[
571
- r.id,
572
- r
573
- ]));
574
- return validPermissions.filter((p)=>roleMap.has(p.targetId)).map((p)=>{
575
- const role = roleMap.get(p.targetId);
576
- return {
577
- id: p.id,
578
- userId: p.sourceId,
579
- roleId: role.id,
580
- roleName: role.name,
581
- branchId: enableCompanyFeature ? p.branchId ?? null : null,
582
- createdAt: p.createdAt
583
- };
584
- });
585
- }
586
- /** Get user's effective actions: company-wide (branchId null) merged with branch-specific */ async getUserEffectiveActions(userId, companyId, branchId) {
587
- const permissionRepo = await this.getPermissionRepository();
588
- const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
589
- const baseWhere = {
590
- permissionType: IamPermissionType.USER_ACTION,
591
- sourceType: IamEntityType.USER,
592
- sourceId: userId
593
- };
594
- if (enableCompanyFeature && companyId) baseWhere.companyId = companyId;
595
- const permissions = enableCompanyFeature && branchId ? await permissionRepo.find({
596
- where: [
597
- {
598
- ...baseWhere,
599
- branchId: IsNull()
600
- },
601
- {
602
- ...baseWhere,
603
- branchId
604
- }
605
- ]
606
- }) : await permissionRepo.find({
607
- where: baseWhere
608
- });
609
- const validPermissions = permissions.filter((p)=>p.isValid());
610
- if (validPermissions.length === 0) {
611
- return [];
612
- }
613
- const actionIds = [
614
- ...new Set(validPermissions.map((p)=>p.targetId))
615
- ];
616
- const actionMap = await this.getActionsMap(actionIds);
617
- return validPermissions.filter((p)=>actionMap.has(p.targetId)).map((p)=>{
618
- const action = actionMap.get(p.targetId);
619
- return {
620
- id: p.id,
621
- userId: p.sourceId,
622
- actionId: action.id,
623
- actionCode: action.code ?? '',
624
- actionName: action.name,
625
- companyId: ('companyId' in p ? p.companyId : null) ?? null,
626
- branchId: ('branchId' in p ? p.branchId : null) ?? null,
627
- createdAt: p.createdAt
628
- };
629
- });
630
- }
631
- // My Permissions
632
- /** Get user's effective permissions (cache-first approach) */ async getMyPermissions(userId, branchId, companyId, parentCodes) {
633
- return this.permissionCacheService.getMyPermissionsResponse(userId, branchId, companyId, parentCodes);
634
- }
635
- // Helper Methods
636
- /** Split permission items into add and remove arrays */ splitItemsByAction(items) {
637
- return {
638
- toAdd: items.filter((item)=>item.action === PermissionAction.ADD),
639
- toRemove: items.filter((item)=>item.action === PermissionAction.REMOVE)
640
- };
641
- }
642
- async publishAssignmentEvent(entity, targetId, result) {
643
- await publishDomainEvent({
644
- module: IAM_EVENT_MODULE,
645
- entity,
646
- action: IAM_EVENT_ACTIONS.PERMISSIONS_ASSIGNED,
647
- ids: [
648
- targetId
649
- ],
650
- metadata: {
651
- added: result.added,
652
- removed: result.removed,
653
- total: result.total
654
- }
655
- });
656
- }
657
- /** Build standard operation result DTO */ buildOperationResult(_totalItems, added, removed) {
658
- return {
659
- added,
660
- removed,
661
- total: _totalItems
662
- };
663
- }
664
- async revokeCompanyPermissions(companyId) {
665
- if (!this.iamConfigService.isCompanyFeatureEnabled()) {
666
- return;
667
- }
668
- const permissionRepo = await this.getPermissionRepository();
669
- const roleRepo = await this.getRoleRepository();
670
- const dataSource = await this.dataSourceProvider.getDataSource();
671
- const companyRoles = await roleRepo.find({
672
- where: {
673
- companyId,
674
- deletedAt: IsNull()
675
- },
676
- select: [
677
- 'id'
678
- ]
679
- });
680
- const roleIds = companyRoles.map((role)=>role.id);
681
- const affectedUserRows = await permissionRepo.find({
682
- where: {
683
- permissionType: In([
684
- IamPermissionType.USER_ROLE,
685
- IamPermissionType.USER_ACTION
686
- ]),
687
- sourceType: IamEntityType.USER,
688
- companyId
689
- },
690
- select: [
691
- 'sourceId'
692
- ]
693
- });
694
- const affectedUserIds = [
695
- ...new Set(affectedUserRows.map((row)=>row.sourceId))
696
- ];
697
- await dataSource.transaction(async (manager)=>{
698
- const txRepo = manager.getRepository(permissionRepo.target);
699
- await txRepo.delete({
700
- permissionType: IamPermissionType.COMPANY_ACTION,
701
- sourceType: IamEntityType.COMPANY,
702
- sourceId: companyId
703
- });
704
- if (roleIds.length > 0) {
705
- await txRepo.delete({
706
- permissionType: IamPermissionType.ROLE_ACTION,
707
- sourceType: IamEntityType.ROLE,
708
- sourceId: In(roleIds)
709
- });
710
- }
711
- await txRepo.delete({
712
- permissionType: In([
713
- IamPermissionType.USER_ROLE,
714
- IamPermissionType.USER_ACTION
715
- ]),
716
- companyId
717
- });
718
- if (roleIds.length > 0) {
719
- const txRoleRepo = manager.getRepository(roleRepo.target);
720
- await txRoleRepo.delete(roleIds);
721
- }
722
- });
723
- if (affectedUserIds.length > 0) {
724
- await this.permissionCacheService.invalidateUsers(affectedUserIds, companyId);
725
- }
726
- }
727
- async revokeBranchPermissions(branchId, companyId) {
728
- if (!this.iamConfigService.isCompanyFeatureEnabled()) {
729
- return;
730
- }
731
- const permissionRepo = await this.getPermissionRepository();
732
- const where = {
733
- permissionType: In([
734
- IamPermissionType.USER_ROLE,
735
- IamPermissionType.USER_ACTION
736
- ]),
737
- companyId,
738
- branchId
739
- };
740
- const affectedUserRows = await permissionRepo.find({
741
- where: {
742
- ...where,
743
- sourceType: IamEntityType.USER
744
- },
745
- select: [
746
- 'sourceId'
747
- ]
748
- });
749
- const affectedUserIds = [
750
- ...new Set(affectedUserRows.map((row)=>row.sourceId))
751
- ];
752
- await permissionRepo.delete(where);
753
- if (affectedUserIds.length > 0) {
754
- await this.permissionCacheService.invalidateUsers(affectedUserIds, companyId, [
755
- branchId
756
- ]);
757
- }
758
- }
759
- async revokeUserCompanyAccess(userId, companyId) {
760
- const permissionRepo = await this.getPermissionRepository();
761
- await permissionRepo.delete({
762
- permissionType: In([
763
- IamPermissionType.USER_ROLE,
764
- IamPermissionType.USER_ACTION
765
- ]),
766
- sourceType: IamEntityType.USER,
767
- sourceId: userId,
768
- companyId
769
- });
770
- await this.permissionCacheService.invalidateUser(userId, companyId);
771
- }
772
- async revokeUserBranchAccess(userId, branchId, companyId) {
773
- const permissionRepo = await this.getPermissionRepository();
774
- const where = {
775
- permissionType: In([
776
- IamPermissionType.USER_ROLE,
777
- IamPermissionType.USER_ACTION
778
- ]),
779
- sourceType: IamEntityType.USER,
780
- sourceId: userId,
781
- branchId,
782
- companyId
783
- };
784
- await permissionRepo.delete(where);
785
- await this.permissionCacheService.invalidateUser(userId, companyId, [
786
- branchId
787
- ]);
788
- }
789
- // NOTE: @Inject() required for bundled code - type metadata may be lost during esbuild
790
- constructor(permissionCacheService, iamConfigService, dataSourceProvider){
791
- _define_property(this, "permissionCacheService", void 0);
792
- _define_property(this, "iamConfigService", void 0);
793
- _define_property(this, "dataSourceProvider", void 0);
794
- this.permissionCacheService = permissionCacheService;
795
- this.iamConfigService = iamConfigService;
796
- this.dataSourceProvider = dataSourceProvider;
797
- }
798
- }
799
- _ts_decorate([
800
- LogAction({
801
- action: 'iam.assignUserActions',
802
- module: 'iam'
803
- }),
804
- _ts_metadata("design:type", Function),
805
- _ts_metadata("design:paramtypes", [
806
- typeof AssignUserActionsDto === "undefined" ? Object : AssignUserActionsDto
807
- ]),
808
- _ts_metadata("design:returntype", Promise)
809
- ], PermissionService.prototype, "assignUserActions", null);
810
- _ts_decorate([
811
- LogAction({
812
- action: 'iam.assignRoleActions',
813
- module: 'iam'
814
- }),
815
- _ts_metadata("design:type", Function),
816
- _ts_metadata("design:paramtypes", [
817
- typeof AssignRoleActionsDto === "undefined" ? Object : AssignRoleActionsDto
818
- ]),
819
- _ts_metadata("design:returntype", Promise)
820
- ], PermissionService.prototype, "assignRoleActions", null);
821
- _ts_decorate([
822
- LogAction({
823
- action: 'iam.assignCompanyActions',
824
- module: 'iam'
825
- }),
826
- _ts_metadata("design:type", Function),
827
- _ts_metadata("design:paramtypes", [
828
- typeof AssignCompanyActionsDto === "undefined" ? Object : AssignCompanyActionsDto
829
- ]),
830
- _ts_metadata("design:returntype", Promise)
831
- ], PermissionService.prototype, "assignCompanyActions", null);
832
- _ts_decorate([
833
- LogAction({
834
- action: 'iam.assignUserRoles',
835
- module: 'iam'
836
- }),
837
- _ts_metadata("design:type", Function),
838
- _ts_metadata("design:paramtypes", [
839
- typeof AssignUserRolesDto === "undefined" ? Object : AssignUserRolesDto
840
- ]),
841
- _ts_metadata("design:returntype", Promise)
842
- ], PermissionService.prototype, "assignUserRoles", null);
843
- _ts_decorate([
844
- LogAction({
845
- action: 'iam.revokeCompanyPermissions',
846
- module: 'iam'
847
- }),
848
- _ts_metadata("design:type", Function),
849
- _ts_metadata("design:paramtypes", [
850
- String
851
- ]),
852
- _ts_metadata("design:returntype", Promise)
853
- ], PermissionService.prototype, "revokeCompanyPermissions", null);
854
- _ts_decorate([
855
- LogAction({
856
- action: 'iam.revokeBranchPermissions',
857
- module: 'iam'
858
- }),
859
- _ts_metadata("design:type", Function),
860
- _ts_metadata("design:paramtypes", [
861
- String,
862
- String
863
- ]),
864
- _ts_metadata("design:returntype", Promise)
865
- ], PermissionService.prototype, "revokeBranchPermissions", null);
866
- _ts_decorate([
867
- LogAction({
868
- action: 'iam.revokeUserCompanyAccess',
869
- module: 'iam'
870
- }),
871
- _ts_metadata("design:type", Function),
872
- _ts_metadata("design:paramtypes", [
873
- String,
874
- String
875
- ]),
876
- _ts_metadata("design:returntype", Promise)
877
- ], PermissionService.prototype, "revokeUserCompanyAccess", null);
878
- _ts_decorate([
879
- LogAction({
880
- action: 'iam.revokeUserBranchAccess',
881
- module: 'iam'
882
- }),
883
- _ts_metadata("design:type", Function),
884
- _ts_metadata("design:paramtypes", [
885
- String,
886
- String,
887
- String
888
- ]),
889
- _ts_metadata("design:returntype", Promise)
890
- ], PermissionService.prototype, "revokeUserBranchAccess", null);
891
- PermissionService = _ts_decorate([
892
- Injectable({
893
- scope: Scope.REQUEST
894
- }),
895
- _ts_param(0, Inject(PermissionCacheService)),
896
- _ts_param(1, Inject(IAMConfigService)),
897
- _ts_param(2, Inject(IAMDataSourceService)),
898
- _ts_metadata("design:type", Function),
899
- _ts_metadata("design:paramtypes", [
900
- typeof PermissionCacheService === "undefined" ? Object : PermissionCacheService,
901
- typeof IAMConfigService === "undefined" ? Object : IAMConfigService,
902
- typeof IAMDataSourceService === "undefined" ? Object : IAMDataSourceService
903
- ])
904
- ], PermissionService);