@flusys/nestjs-iam 3.0.0 → 4.0.0-rc
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/README.md +1 -1
- package/cjs/config/index.js +1 -0
- package/cjs/config/message-keys.js +102 -0
- package/cjs/controllers/action.controller.js +4 -0
- package/cjs/controllers/company-action-permission.controller.js +2 -0
- package/cjs/controllers/my-permission.controller.js +2 -0
- package/cjs/controllers/role-permission.controller.js +5 -2
- package/cjs/controllers/role.controller.js +1 -0
- package/cjs/controllers/user-action-permission.controller.js +4 -2
- package/cjs/dtos/permission.dto.js +8 -0
- package/cjs/helpers/company-access.helper.js +6 -2
- package/cjs/services/action.service.js +9 -2
- package/cjs/services/iam-datasource.service.js +7 -3
- package/cjs/services/permission-cache.service.js +97 -71
- package/cjs/services/permission.service.js +72 -12
- package/cjs/services/role.service.js +1 -1
- package/config/index.d.ts +1 -0
- package/config/message-keys.d.ts +106 -0
- package/dtos/permission.dto.d.ts +1 -0
- package/fesm/config/index.js +1 -0
- package/fesm/config/message-keys.js +64 -0
- package/fesm/controllers/action.controller.js +4 -0
- package/fesm/controllers/company-action-permission.controller.js +2 -0
- package/fesm/controllers/my-permission.controller.js +2 -0
- package/fesm/controllers/role-permission.controller.js +5 -2
- package/fesm/controllers/role.controller.js +1 -0
- package/fesm/controllers/user-action-permission.controller.js +4 -2
- package/fesm/dtos/permission.dto.js +8 -0
- package/fesm/helpers/company-access.helper.js +6 -2
- package/fesm/services/action.service.js +9 -2
- package/fesm/services/iam-datasource.service.js +8 -4
- package/fesm/services/permission-cache.service.js +99 -73
- package/fesm/services/permission.service.js +74 -14
- package/fesm/services/role.service.js +1 -1
- package/helpers/company-access.helper.d.ts +1 -1
- package/package.json +3 -3
- package/services/iam-datasource.service.d.ts +0 -2
- package/services/permission-cache.service.d.ts +1 -2
- package/services/permission.service.d.ts +0 -1
|
@@ -8,6 +8,8 @@ Object.defineProperty(exports, "PermissionService", {
|
|
|
8
8
|
return PermissionService;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
const _config = require("../config");
|
|
12
|
+
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
11
13
|
const _common = require("@nestjs/common");
|
|
12
14
|
const _typeorm = require("typeorm");
|
|
13
15
|
const _permissiondto = require("../dtos/permission.dto");
|
|
@@ -66,7 +68,10 @@ let PermissionService = class PermissionService {
|
|
|
66
68
|
// User-Action Permissions
|
|
67
69
|
async assignUserActions(dto) {
|
|
68
70
|
if (!this.iamConfigService.isDirectPermissionEnabled()) {
|
|
69
|
-
throw new _common.BadRequestException(
|
|
71
|
+
throw new _common.BadRequestException({
|
|
72
|
+
message: 'Direct permission assignment not available in RBAC-only mode. Use role-based permissions instead.',
|
|
73
|
+
messageKey: _config.IAM_MODE_MESSAGES.DIRECT_MODE_UNAVAILABLE
|
|
74
|
+
});
|
|
70
75
|
}
|
|
71
76
|
const permissionRepo = await this.getPermissionRepository();
|
|
72
77
|
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
@@ -111,7 +116,10 @@ let PermissionService = class PermissionService {
|
|
|
111
116
|
added = newPermissions.length;
|
|
112
117
|
} catch (error) {
|
|
113
118
|
if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
|
|
114
|
-
throw new _common.ConflictException(
|
|
119
|
+
throw new _common.ConflictException({
|
|
120
|
+
message: 'Some permissions already exist for this user. Please refresh and try again.',
|
|
121
|
+
messageKey: _config.PERMISSION_OPERATION_MESSAGES.ALREADY_EXISTS
|
|
122
|
+
});
|
|
115
123
|
}
|
|
116
124
|
throw error;
|
|
117
125
|
}
|
|
@@ -182,7 +190,10 @@ let PermissionService = class PermissionService {
|
|
|
182
190
|
// Role-Action Permissions
|
|
183
191
|
async assignRoleActions(dto) {
|
|
184
192
|
if (!this.iamConfigService.isRbacEnabled()) {
|
|
185
|
-
throw new _common.BadRequestException(
|
|
193
|
+
throw new _common.BadRequestException({
|
|
194
|
+
message: 'Role-based permission assignment not available in DIRECT-only mode. Use direct user permissions instead.',
|
|
195
|
+
messageKey: _config.IAM_MODE_MESSAGES.RBAC_MODE_UNAVAILABLE
|
|
196
|
+
});
|
|
186
197
|
}
|
|
187
198
|
const permissionRepo = await this.getPermissionRepository();
|
|
188
199
|
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
@@ -234,7 +245,10 @@ let PermissionService = class PermissionService {
|
|
|
234
245
|
added = newPermissions.length;
|
|
235
246
|
} catch (error) {
|
|
236
247
|
if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
|
|
237
|
-
throw new _common.ConflictException(
|
|
248
|
+
throw new _common.ConflictException({
|
|
249
|
+
message: 'Some role-action permissions already exist. Please refresh and try again.',
|
|
250
|
+
messageKey: _config.PERMISSION_OPERATION_MESSAGES.ALREADY_EXISTS
|
|
251
|
+
});
|
|
238
252
|
}
|
|
239
253
|
throw error;
|
|
240
254
|
}
|
|
@@ -388,9 +402,6 @@ let PermissionService = class PermissionService {
|
|
|
388
402
|
});
|
|
389
403
|
removedUserActions = userResult.affected || 0;
|
|
390
404
|
}
|
|
391
|
-
if (removedRoleActions > 0 || removedUserActions > 0) {
|
|
392
|
-
this.logger.log(`Cascade deleted for company ${companyId}: ${removedRoleActions} role actions, ${removedUserActions} user actions`);
|
|
393
|
-
}
|
|
394
405
|
return {
|
|
395
406
|
removedCompanyActions: companyResult.affected || 0,
|
|
396
407
|
removedRoleActions,
|
|
@@ -449,7 +460,10 @@ let PermissionService = class PermissionService {
|
|
|
449
460
|
// User-Role Permissions
|
|
450
461
|
/** Assign user to roles (branch-scoped when company feature is enabled) */ async assignUserRoles(dto) {
|
|
451
462
|
if (!this.iamConfigService.isRbacEnabled()) {
|
|
452
|
-
throw new _common.BadRequestException(
|
|
463
|
+
throw new _common.BadRequestException({
|
|
464
|
+
message: 'Role assignment not available in DIRECT-only mode. Use direct user permissions instead.',
|
|
465
|
+
messageKey: _config.IAM_MODE_MESSAGES.ROLE_ASSIGNMENT_UNAVAILABLE
|
|
466
|
+
});
|
|
453
467
|
}
|
|
454
468
|
const permissionRepo = await this.getPermissionRepository();
|
|
455
469
|
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
@@ -494,7 +508,10 @@ let PermissionService = class PermissionService {
|
|
|
494
508
|
added = newPermissions.length;
|
|
495
509
|
} catch (error) {
|
|
496
510
|
if (error?.code === 'ER_DUP_ENTRY' || error?.message?.includes('Duplicate entry')) {
|
|
497
|
-
throw new _common.ConflictException(
|
|
511
|
+
throw new _common.ConflictException({
|
|
512
|
+
message: 'Some user-role permissions already exist. Please refresh and try again.',
|
|
513
|
+
messageKey: _config.PERMISSION_OPERATION_MESSAGES.ALREADY_EXISTS
|
|
514
|
+
});
|
|
498
515
|
}
|
|
499
516
|
throw error;
|
|
500
517
|
}
|
|
@@ -720,7 +737,8 @@ let PermissionService = class PermissionService {
|
|
|
720
737
|
success: true,
|
|
721
738
|
added,
|
|
722
739
|
removed,
|
|
723
|
-
message: `Successfully processed ${totalItems} items: ${added} added, ${removed} removed${additionalMessage}
|
|
740
|
+
message: `Successfully processed ${totalItems} items: ${added} added, ${removed} removed${additionalMessage}`,
|
|
741
|
+
messageKey: _config.PERMISSION_OPERATION_MESSAGES.PROCESS_SUCCESS
|
|
724
742
|
};
|
|
725
743
|
}
|
|
726
744
|
/** Get role IDs assigned to a user (merges company-wide + branch-specific roles) */ async getUserRoleIds(userId, branchId, companyId) {
|
|
@@ -897,13 +915,55 @@ let PermissionService = class PermissionService {
|
|
|
897
915
|
_define_property(this, "permissionCacheService", void 0);
|
|
898
916
|
_define_property(this, "iamConfigService", void 0);
|
|
899
917
|
_define_property(this, "dataSourceProvider", void 0);
|
|
900
|
-
_define_property(this, "logger", void 0);
|
|
901
918
|
this.permissionCacheService = permissionCacheService;
|
|
902
919
|
this.iamConfigService = iamConfigService;
|
|
903
920
|
this.dataSourceProvider = dataSourceProvider;
|
|
904
|
-
this.logger = new _common.Logger(PermissionService.name);
|
|
905
921
|
}
|
|
906
922
|
};
|
|
923
|
+
_ts_decorate([
|
|
924
|
+
(0, _nestjsshared.LogAction)({
|
|
925
|
+
action: 'iam.assignUserActions',
|
|
926
|
+
module: 'iam'
|
|
927
|
+
}),
|
|
928
|
+
_ts_metadata("design:type", Function),
|
|
929
|
+
_ts_metadata("design:paramtypes", [
|
|
930
|
+
typeof _permissiondto.AssignUserActionsDto === "undefined" ? Object : _permissiondto.AssignUserActionsDto
|
|
931
|
+
]),
|
|
932
|
+
_ts_metadata("design:returntype", Promise)
|
|
933
|
+
], PermissionService.prototype, "assignUserActions", null);
|
|
934
|
+
_ts_decorate([
|
|
935
|
+
(0, _nestjsshared.LogAction)({
|
|
936
|
+
action: 'iam.assignRoleActions',
|
|
937
|
+
module: 'iam'
|
|
938
|
+
}),
|
|
939
|
+
_ts_metadata("design:type", Function),
|
|
940
|
+
_ts_metadata("design:paramtypes", [
|
|
941
|
+
typeof _permissiondto.AssignRoleActionsDto === "undefined" ? Object : _permissiondto.AssignRoleActionsDto
|
|
942
|
+
]),
|
|
943
|
+
_ts_metadata("design:returntype", Promise)
|
|
944
|
+
], PermissionService.prototype, "assignRoleActions", null);
|
|
945
|
+
_ts_decorate([
|
|
946
|
+
(0, _nestjsshared.LogAction)({
|
|
947
|
+
action: 'iam.assignCompanyActions',
|
|
948
|
+
module: 'iam'
|
|
949
|
+
}),
|
|
950
|
+
_ts_metadata("design:type", Function),
|
|
951
|
+
_ts_metadata("design:paramtypes", [
|
|
952
|
+
typeof _permissiondto.AssignCompanyActionsDto === "undefined" ? Object : _permissiondto.AssignCompanyActionsDto
|
|
953
|
+
]),
|
|
954
|
+
_ts_metadata("design:returntype", Promise)
|
|
955
|
+
], PermissionService.prototype, "assignCompanyActions", null);
|
|
956
|
+
_ts_decorate([
|
|
957
|
+
(0, _nestjsshared.LogAction)({
|
|
958
|
+
action: 'iam.assignUserRoles',
|
|
959
|
+
module: 'iam'
|
|
960
|
+
}),
|
|
961
|
+
_ts_metadata("design:type", Function),
|
|
962
|
+
_ts_metadata("design:paramtypes", [
|
|
963
|
+
typeof _permissiondto.AssignUserRolesDto === "undefined" ? Object : _permissiondto.AssignUserRolesDto
|
|
964
|
+
]),
|
|
965
|
+
_ts_metadata("design:returntype", Promise)
|
|
966
|
+
], PermissionService.prototype, "assignUserRoles", null);
|
|
907
967
|
PermissionService = _ts_decorate([
|
|
908
968
|
(0, _common.Injectable)({
|
|
909
969
|
scope: _common.Scope.REQUEST
|
|
@@ -122,7 +122,7 @@ let RoleService = class RoleService extends _classes.RequestScopedApiService {
|
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider){
|
|
125
|
-
super('role', null, cacheManager, utilsService, RoleService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.dataSourceProvider = dataSourceProvider;
|
|
125
|
+
super('role', null, cacheManager, utilsService, RoleService.name, true, 'iam'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.dataSourceProvider = dataSourceProvider;
|
|
126
126
|
}
|
|
127
127
|
};
|
|
128
128
|
RoleService = _ts_decorate([
|
package/config/index.d.ts
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export declare const ACTION_MESSAGES: {
|
|
2
|
+
readonly CREATE_SUCCESS: "action.create.success";
|
|
3
|
+
readonly CREATE_MANY_SUCCESS: "action.create.many.success";
|
|
4
|
+
readonly GET_SUCCESS: "action.get.success";
|
|
5
|
+
readonly GET_ALL_SUCCESS: "action.get.all.success";
|
|
6
|
+
readonly UPDATE_SUCCESS: "action.update.success";
|
|
7
|
+
readonly UPDATE_MANY_SUCCESS: "action.update.many.success";
|
|
8
|
+
readonly DELETE_SUCCESS: "action.delete.success";
|
|
9
|
+
readonly RESTORE_SUCCESS: "action.restore.success";
|
|
10
|
+
readonly NOT_FOUND: "action.not.found";
|
|
11
|
+
};
|
|
12
|
+
export declare const ROLE_MESSAGES: {
|
|
13
|
+
readonly CREATE_SUCCESS: "role.create.success";
|
|
14
|
+
readonly CREATE_MANY_SUCCESS: "role.create.many.success";
|
|
15
|
+
readonly GET_SUCCESS: "role.get.success";
|
|
16
|
+
readonly GET_ALL_SUCCESS: "role.get.all.success";
|
|
17
|
+
readonly UPDATE_SUCCESS: "role.update.success";
|
|
18
|
+
readonly UPDATE_MANY_SUCCESS: "role.update.many.success";
|
|
19
|
+
readonly DELETE_SUCCESS: "role.delete.success";
|
|
20
|
+
readonly RESTORE_SUCCESS: "role.restore.success";
|
|
21
|
+
readonly NOT_FOUND: "role.not.found";
|
|
22
|
+
};
|
|
23
|
+
export declare const ROLE_PERMISSION_MESSAGES: {
|
|
24
|
+
readonly GET_SUCCESS: "role.permission.get.success";
|
|
25
|
+
readonly ASSIGN_SUCCESS: "role.permission.assign.success";
|
|
26
|
+
readonly ACTIONS_SUCCESS: "role.permission.actions.success";
|
|
27
|
+
readonly USERS_SUCCESS: "role.permission.users.success";
|
|
28
|
+
readonly USER_ROLES_SUCCESS: "role.permission.user.roles.success";
|
|
29
|
+
};
|
|
30
|
+
export declare const USER_ACTION_PERMISSION_MESSAGES: {
|
|
31
|
+
readonly GET_SUCCESS: "user.action.permission.get.success";
|
|
32
|
+
readonly ASSIGN_SUCCESS: "user.action.permission.assign.success";
|
|
33
|
+
readonly REVOKE_SUCCESS: "user.action.permission.revoke.success";
|
|
34
|
+
};
|
|
35
|
+
export declare const COMPANY_ACTION_PERMISSION_MESSAGES: {
|
|
36
|
+
readonly GET_SUCCESS: "company.action.permission.get.success";
|
|
37
|
+
readonly ASSIGN_SUCCESS: "company.action.permission.assign.success";
|
|
38
|
+
readonly REVOKE_SUCCESS: "company.action.permission.revoke.success";
|
|
39
|
+
};
|
|
40
|
+
export declare const MY_PERMISSION_MESSAGES: {
|
|
41
|
+
readonly GET_SUCCESS: "my.permission.get.success";
|
|
42
|
+
};
|
|
43
|
+
export declare const IAM_MODE_MESSAGES: {
|
|
44
|
+
readonly DIRECT_MODE_UNAVAILABLE: "iam.direct.mode.unavailable";
|
|
45
|
+
readonly RBAC_MODE_UNAVAILABLE: "iam.rbac.mode.unavailable";
|
|
46
|
+
readonly ROLE_ASSIGNMENT_UNAVAILABLE: "iam.role.assignment.unavailable";
|
|
47
|
+
};
|
|
48
|
+
export declare const PERMISSION_OPERATION_MESSAGES: {
|
|
49
|
+
readonly PROCESS_SUCCESS: "permission.process.success";
|
|
50
|
+
readonly ALREADY_EXISTS: "permission.already.exists";
|
|
51
|
+
readonly USER_REQUIRED: "permission.user.required";
|
|
52
|
+
};
|
|
53
|
+
export declare const IAM_MODULE_MESSAGES: {
|
|
54
|
+
readonly ACTION: {
|
|
55
|
+
readonly CREATE_SUCCESS: "action.create.success";
|
|
56
|
+
readonly CREATE_MANY_SUCCESS: "action.create.many.success";
|
|
57
|
+
readonly GET_SUCCESS: "action.get.success";
|
|
58
|
+
readonly GET_ALL_SUCCESS: "action.get.all.success";
|
|
59
|
+
readonly UPDATE_SUCCESS: "action.update.success";
|
|
60
|
+
readonly UPDATE_MANY_SUCCESS: "action.update.many.success";
|
|
61
|
+
readonly DELETE_SUCCESS: "action.delete.success";
|
|
62
|
+
readonly RESTORE_SUCCESS: "action.restore.success";
|
|
63
|
+
readonly NOT_FOUND: "action.not.found";
|
|
64
|
+
};
|
|
65
|
+
readonly ROLE: {
|
|
66
|
+
readonly CREATE_SUCCESS: "role.create.success";
|
|
67
|
+
readonly CREATE_MANY_SUCCESS: "role.create.many.success";
|
|
68
|
+
readonly GET_SUCCESS: "role.get.success";
|
|
69
|
+
readonly GET_ALL_SUCCESS: "role.get.all.success";
|
|
70
|
+
readonly UPDATE_SUCCESS: "role.update.success";
|
|
71
|
+
readonly UPDATE_MANY_SUCCESS: "role.update.many.success";
|
|
72
|
+
readonly DELETE_SUCCESS: "role.delete.success";
|
|
73
|
+
readonly RESTORE_SUCCESS: "role.restore.success";
|
|
74
|
+
readonly NOT_FOUND: "role.not.found";
|
|
75
|
+
};
|
|
76
|
+
readonly ROLE_PERMISSION: {
|
|
77
|
+
readonly GET_SUCCESS: "role.permission.get.success";
|
|
78
|
+
readonly ASSIGN_SUCCESS: "role.permission.assign.success";
|
|
79
|
+
readonly ACTIONS_SUCCESS: "role.permission.actions.success";
|
|
80
|
+
readonly USERS_SUCCESS: "role.permission.users.success";
|
|
81
|
+
readonly USER_ROLES_SUCCESS: "role.permission.user.roles.success";
|
|
82
|
+
};
|
|
83
|
+
readonly USER_ACTION_PERMISSION: {
|
|
84
|
+
readonly GET_SUCCESS: "user.action.permission.get.success";
|
|
85
|
+
readonly ASSIGN_SUCCESS: "user.action.permission.assign.success";
|
|
86
|
+
readonly REVOKE_SUCCESS: "user.action.permission.revoke.success";
|
|
87
|
+
};
|
|
88
|
+
readonly COMPANY_ACTION_PERMISSION: {
|
|
89
|
+
readonly GET_SUCCESS: "company.action.permission.get.success";
|
|
90
|
+
readonly ASSIGN_SUCCESS: "company.action.permission.assign.success";
|
|
91
|
+
readonly REVOKE_SUCCESS: "company.action.permission.revoke.success";
|
|
92
|
+
};
|
|
93
|
+
readonly MY_PERMISSION: {
|
|
94
|
+
readonly GET_SUCCESS: "my.permission.get.success";
|
|
95
|
+
};
|
|
96
|
+
readonly IAM_MODE: {
|
|
97
|
+
readonly DIRECT_MODE_UNAVAILABLE: "iam.direct.mode.unavailable";
|
|
98
|
+
readonly RBAC_MODE_UNAVAILABLE: "iam.rbac.mode.unavailable";
|
|
99
|
+
readonly ROLE_ASSIGNMENT_UNAVAILABLE: "iam.role.assignment.unavailable";
|
|
100
|
+
};
|
|
101
|
+
readonly PERMISSION_OPERATION: {
|
|
102
|
+
readonly PROCESS_SUCCESS: "permission.process.success";
|
|
103
|
+
readonly ALREADY_EXISTS: "permission.already.exists";
|
|
104
|
+
readonly USER_REQUIRED: "permission.user.required";
|
|
105
|
+
};
|
|
106
|
+
};
|
package/dtos/permission.dto.d.ts
CHANGED
package/fesm/config/index.js
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ==================== IAM MODULE MESSAGE KEYS ====================
|
|
2
|
+
export const ACTION_MESSAGES = {
|
|
3
|
+
CREATE_SUCCESS: 'action.create.success',
|
|
4
|
+
CREATE_MANY_SUCCESS: 'action.create.many.success',
|
|
5
|
+
GET_SUCCESS: 'action.get.success',
|
|
6
|
+
GET_ALL_SUCCESS: 'action.get.all.success',
|
|
7
|
+
UPDATE_SUCCESS: 'action.update.success',
|
|
8
|
+
UPDATE_MANY_SUCCESS: 'action.update.many.success',
|
|
9
|
+
DELETE_SUCCESS: 'action.delete.success',
|
|
10
|
+
RESTORE_SUCCESS: 'action.restore.success',
|
|
11
|
+
NOT_FOUND: 'action.not.found'
|
|
12
|
+
};
|
|
13
|
+
export const ROLE_MESSAGES = {
|
|
14
|
+
CREATE_SUCCESS: 'role.create.success',
|
|
15
|
+
CREATE_MANY_SUCCESS: 'role.create.many.success',
|
|
16
|
+
GET_SUCCESS: 'role.get.success',
|
|
17
|
+
GET_ALL_SUCCESS: 'role.get.all.success',
|
|
18
|
+
UPDATE_SUCCESS: 'role.update.success',
|
|
19
|
+
UPDATE_MANY_SUCCESS: 'role.update.many.success',
|
|
20
|
+
DELETE_SUCCESS: 'role.delete.success',
|
|
21
|
+
RESTORE_SUCCESS: 'role.restore.success',
|
|
22
|
+
NOT_FOUND: 'role.not.found'
|
|
23
|
+
};
|
|
24
|
+
export const ROLE_PERMISSION_MESSAGES = {
|
|
25
|
+
GET_SUCCESS: 'role.permission.get.success',
|
|
26
|
+
ASSIGN_SUCCESS: 'role.permission.assign.success',
|
|
27
|
+
ACTIONS_SUCCESS: 'role.permission.actions.success',
|
|
28
|
+
USERS_SUCCESS: 'role.permission.users.success',
|
|
29
|
+
USER_ROLES_SUCCESS: 'role.permission.user.roles.success'
|
|
30
|
+
};
|
|
31
|
+
export const USER_ACTION_PERMISSION_MESSAGES = {
|
|
32
|
+
GET_SUCCESS: 'user.action.permission.get.success',
|
|
33
|
+
ASSIGN_SUCCESS: 'user.action.permission.assign.success',
|
|
34
|
+
REVOKE_SUCCESS: 'user.action.permission.revoke.success'
|
|
35
|
+
};
|
|
36
|
+
export const COMPANY_ACTION_PERMISSION_MESSAGES = {
|
|
37
|
+
GET_SUCCESS: 'company.action.permission.get.success',
|
|
38
|
+
ASSIGN_SUCCESS: 'company.action.permission.assign.success',
|
|
39
|
+
REVOKE_SUCCESS: 'company.action.permission.revoke.success'
|
|
40
|
+
};
|
|
41
|
+
export const MY_PERMISSION_MESSAGES = {
|
|
42
|
+
GET_SUCCESS: 'my.permission.get.success'
|
|
43
|
+
};
|
|
44
|
+
export const IAM_MODE_MESSAGES = {
|
|
45
|
+
DIRECT_MODE_UNAVAILABLE: 'iam.direct.mode.unavailable',
|
|
46
|
+
RBAC_MODE_UNAVAILABLE: 'iam.rbac.mode.unavailable',
|
|
47
|
+
ROLE_ASSIGNMENT_UNAVAILABLE: 'iam.role.assignment.unavailable'
|
|
48
|
+
};
|
|
49
|
+
export const PERMISSION_OPERATION_MESSAGES = {
|
|
50
|
+
PROCESS_SUCCESS: 'permission.process.success',
|
|
51
|
+
ALREADY_EXISTS: 'permission.already.exists',
|
|
52
|
+
USER_REQUIRED: 'permission.user.required'
|
|
53
|
+
};
|
|
54
|
+
// Aggregated export for backward compatibility
|
|
55
|
+
export const IAM_MODULE_MESSAGES = {
|
|
56
|
+
ACTION: ACTION_MESSAGES,
|
|
57
|
+
ROLE: ROLE_MESSAGES,
|
|
58
|
+
ROLE_PERMISSION: ROLE_PERMISSION_MESSAGES,
|
|
59
|
+
USER_ACTION_PERMISSION: USER_ACTION_PERMISSION_MESSAGES,
|
|
60
|
+
COMPANY_ACTION_PERMISSION: COMPANY_ACTION_PERMISSION_MESSAGES,
|
|
61
|
+
MY_PERMISSION: MY_PERMISSION_MESSAGES,
|
|
62
|
+
IAM_MODE: IAM_MODE_MESSAGES,
|
|
63
|
+
PERMISSION_OPERATION: PERMISSION_OPERATION_MESSAGES
|
|
64
|
+
};
|
|
@@ -27,11 +27,13 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
}
|
|
28
28
|
import { JwtAuthGuard } from '@flusys/nestjs-shared/guards';
|
|
29
29
|
import { createApiController, CurrentUser, ILoggedUserInfo, SingleResponseDto, ACTION_PERMISSIONS } from '@flusys/nestjs-shared';
|
|
30
|
+
import { ACTION_MESSAGES } from '../config';
|
|
30
31
|
import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
|
|
31
32
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
32
33
|
import { ActionResponseDto, ActionTreeQueryDto, CreateActionDto, UpdateActionDto } from '../dtos/action.dto';
|
|
33
34
|
import { ActionService } from '../services/action.service';
|
|
34
35
|
export class ActionController extends createApiController(CreateActionDto, UpdateActionDto, ActionResponseDto, {
|
|
36
|
+
entityName: 'action',
|
|
35
37
|
security: {
|
|
36
38
|
insert: {
|
|
37
39
|
level: 'permission',
|
|
@@ -82,6 +84,7 @@ export class ActionController extends createApiController(CreateActionDto, Updat
|
|
|
82
84
|
return {
|
|
83
85
|
success: true,
|
|
84
86
|
message: 'Actions retrieved successfully',
|
|
87
|
+
messageKey: ACTION_MESSAGES.GET_ALL_SUCCESS,
|
|
85
88
|
data: actions
|
|
86
89
|
};
|
|
87
90
|
}
|
|
@@ -90,6 +93,7 @@ export class ActionController extends createApiController(CreateActionDto, Updat
|
|
|
90
93
|
return {
|
|
91
94
|
success: true,
|
|
92
95
|
message: 'Action tree retrieved successfully',
|
|
96
|
+
messageKey: ACTION_MESSAGES.GET_ALL_SUCCESS,
|
|
93
97
|
data: tree
|
|
94
98
|
};
|
|
95
99
|
}
|
|
@@ -26,6 +26,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { COMPANY_ACTION_PERMISSIONS, CurrentUser, ILoggedUserInfo, JwtAuthGuard, RequirePermission, SingleResponseDto } from '@flusys/nestjs-shared';
|
|
29
|
+
import { COMPANY_ACTION_PERMISSION_MESSAGES } from '../config';
|
|
29
30
|
import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
|
|
30
31
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
31
32
|
import { AssignCompanyActionsDto, GetCompanyActionsDto, PermissionOperationResultDto } from '../dtos/permission.dto';
|
|
@@ -39,6 +40,7 @@ export class CompanyActionPermissionController {
|
|
|
39
40
|
return {
|
|
40
41
|
success: true,
|
|
41
42
|
message: 'Company actions retrieved successfully',
|
|
43
|
+
messageKey: COMPANY_ACTION_PERMISSION_MESSAGES.GET_SUCCESS,
|
|
42
44
|
data: actions
|
|
43
45
|
};
|
|
44
46
|
}
|
|
@@ -26,6 +26,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { CurrentUser, ILoggedUserInfo, JwtAuthGuard } from '@flusys/nestjs-shared';
|
|
29
|
+
import { MY_PERMISSION_MESSAGES } from '../config';
|
|
29
30
|
import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
|
|
30
31
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
31
32
|
import { MyPermissionsQueryDto, MyPermissionsResponseDto } from '../dtos/permission.dto';
|
|
@@ -36,6 +37,7 @@ export class MyPermissionController {
|
|
|
36
37
|
return {
|
|
37
38
|
success: true,
|
|
38
39
|
message: 'Permissions loaded successfully',
|
|
40
|
+
messageKey: MY_PERMISSION_MESSAGES.GET_SUCCESS,
|
|
39
41
|
data
|
|
40
42
|
};
|
|
41
43
|
}
|
|
@@ -26,6 +26,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { JwtAuthGuard, SingleResponseDto, RequirePermission, ROLE_ACTION_PERMISSIONS, USER_ROLE_PERMISSIONS, CurrentUser, ILoggedUserInfo } from '@flusys/nestjs-shared';
|
|
29
|
+
import { ROLE_PERMISSION_MESSAGES } from '../config';
|
|
29
30
|
import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
|
|
30
31
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
31
32
|
import { AssignRoleActionsDto, AssignUserRolesDto, GetRoleActionsDto, GetUserRolesDto, PermissionOperationResultDto } from '../dtos/permission.dto';
|
|
@@ -41,19 +42,21 @@ export class RolePermissionController {
|
|
|
41
42
|
return {
|
|
42
43
|
success: true,
|
|
43
44
|
message: 'Role actions retrieved successfully',
|
|
45
|
+
messageKey: ROLE_PERMISSION_MESSAGES.ACTIONS_SUCCESS,
|
|
44
46
|
data: actions
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
async assignUserRoles(dto, user) {
|
|
48
|
-
validateCompanyAccess(this.config, dto.companyId, user
|
|
50
|
+
validateCompanyAccess(this.config, dto.companyId, user);
|
|
49
51
|
return this.permissionService.assignUserRoles(dto);
|
|
50
52
|
}
|
|
51
53
|
async getUserRoles(dto, user) {
|
|
52
|
-
validateCompanyAccess(this.config, dto.companyId, user
|
|
54
|
+
validateCompanyAccess(this.config, dto.companyId, user);
|
|
53
55
|
const roles = await this.permissionService.getUserRoles(dto.userId, dto.branchId, dto.companyId);
|
|
54
56
|
return {
|
|
55
57
|
success: true,
|
|
56
58
|
message: 'User roles retrieved successfully',
|
|
59
|
+
messageKey: ROLE_PERMISSION_MESSAGES.USER_ROLES_SUCCESS,
|
|
57
60
|
data: roles
|
|
58
61
|
};
|
|
59
62
|
}
|
|
@@ -31,6 +31,7 @@ import { ApiTags } from '@nestjs/swagger';
|
|
|
31
31
|
import { CreateRoleDto, RoleResponseDto, UpdateRoleDto } from '../dtos/role.dto';
|
|
32
32
|
import { RoleService } from '../services/role.service';
|
|
33
33
|
export class RoleController extends createApiController(CreateRoleDto, UpdateRoleDto, RoleResponseDto, {
|
|
34
|
+
entityName: 'role',
|
|
34
35
|
security: {
|
|
35
36
|
insert: {
|
|
36
37
|
level: 'permission',
|
|
@@ -26,6 +26,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { JwtAuthGuard, SingleResponseDto, RequirePermission, USER_ACTION_PERMISSIONS, CurrentUser, ILoggedUserInfo } from '@flusys/nestjs-shared';
|
|
29
|
+
import { USER_ACTION_PERMISSION_MESSAGES } from '../config';
|
|
29
30
|
import { Body, Controller, Inject, Post, UseGuards } from '@nestjs/common';
|
|
30
31
|
import { ApiBearerAuth, ApiBody, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
31
32
|
import { AssignUserActionsDto, GetUserActionsDto, PermissionOperationResultDto } from '../dtos/permission.dto';
|
|
@@ -34,15 +35,16 @@ import { PermissionService } from '../services/permission.service';
|
|
|
34
35
|
import { IAMConfigService } from '../services/iam-config.service';
|
|
35
36
|
export class UserActionPermissionController {
|
|
36
37
|
async assignUserActions(dto, user) {
|
|
37
|
-
validateCompanyAccess(this.config, dto.companyId, user
|
|
38
|
+
validateCompanyAccess(this.config, dto.companyId, user);
|
|
38
39
|
return this.permissionService.assignUserActions(dto);
|
|
39
40
|
}
|
|
40
41
|
async getUserActions(dto, user) {
|
|
41
|
-
validateCompanyAccess(this.config, dto.companyId, user
|
|
42
|
+
validateCompanyAccess(this.config, dto.companyId, user);
|
|
42
43
|
const actions = await this.permissionService.getUserActions(dto.userId, dto.branchId, dto.companyId);
|
|
43
44
|
return {
|
|
44
45
|
success: true,
|
|
45
46
|
message: 'User actions retrieved successfully',
|
|
47
|
+
messageKey: USER_ACTION_PERMISSION_MESSAGES.GET_SUCCESS,
|
|
46
48
|
data: actions
|
|
47
49
|
};
|
|
48
50
|
}
|
|
@@ -550,6 +550,7 @@ export class PermissionOperationResultDto {
|
|
|
550
550
|
_define_property(this, "added", void 0);
|
|
551
551
|
_define_property(this, "removed", void 0);
|
|
552
552
|
_define_property(this, "message", void 0);
|
|
553
|
+
_define_property(this, "messageKey", void 0);
|
|
553
554
|
}
|
|
554
555
|
}
|
|
555
556
|
_ts_decorate([
|
|
@@ -576,3 +577,10 @@ _ts_decorate([
|
|
|
576
577
|
}),
|
|
577
578
|
_ts_metadata("design:type", String)
|
|
578
579
|
], PermissionOperationResultDto.prototype, "message", void 0);
|
|
580
|
+
_ts_decorate([
|
|
581
|
+
ApiPropertyOptional({
|
|
582
|
+
description: 'Translation key for localization',
|
|
583
|
+
example: 'permission.process.success'
|
|
584
|
+
}),
|
|
585
|
+
_ts_metadata("design:type", String)
|
|
586
|
+
], PermissionOperationResultDto.prototype, "messageKey", void 0);
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { ForbiddenException } from '@nestjs/common';
|
|
2
|
+
import { AUTH_MESSAGES } from '@flusys/nestjs-shared/constants';
|
|
2
3
|
/**
|
|
3
4
|
* Validates that user has access to the specified company.
|
|
4
5
|
* Used for user-action and role-permission operations when company feature is enabled.
|
|
5
6
|
*
|
|
6
7
|
* @throws ForbiddenException if user doesn't have access to the company
|
|
7
|
-
*/ export function validateCompanyAccess(config, companyId, user, errorMessage = 'You do not have access to this company') {
|
|
8
|
+
*/ export function validateCompanyAccess(config, companyId, user, errorMessage = 'You do not have access to this company', messageKey = AUTH_MESSAGES.COMPANY_NO_ACCESS) {
|
|
8
9
|
if (!config.isCompanyFeatureEnabled() || !companyId) {
|
|
9
10
|
return;
|
|
10
11
|
}
|
|
11
12
|
if (user.companyId !== companyId) {
|
|
12
|
-
throw new ForbiddenException(
|
|
13
|
+
throw new ForbiddenException({
|
|
14
|
+
message: errorMessage,
|
|
15
|
+
messageKey
|
|
16
|
+
});
|
|
13
17
|
}
|
|
14
18
|
}
|
|
@@ -26,6 +26,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { HybridCache, RequestScopedApiService } from '@flusys/nestjs-shared/classes';
|
|
29
|
+
import { PERMISSION_OPERATION_MESSAGES } from '../config';
|
|
29
30
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
30
31
|
import { BadRequestException, Inject, Injectable, Scope } from '@nestjs/common';
|
|
31
32
|
import { In } from 'typeorm';
|
|
@@ -95,7 +96,13 @@ export class ActionService extends RequestScopedApiService {
|
|
|
95
96
|
}
|
|
96
97
|
requireUser(user, methodName) {
|
|
97
98
|
if (!user) {
|
|
98
|
-
throw new BadRequestException(
|
|
99
|
+
throw new BadRequestException({
|
|
100
|
+
message: `User is required for ${methodName}`,
|
|
101
|
+
messageKey: PERMISSION_OPERATION_MESSAGES.USER_REQUIRED,
|
|
102
|
+
messageParams: {
|
|
103
|
+
method: methodName
|
|
104
|
+
}
|
|
105
|
+
});
|
|
99
106
|
}
|
|
100
107
|
}
|
|
101
108
|
/** Get actions available for permission assignment (filtered by company whitelist) */ async getActionsForPermission(user) {
|
|
@@ -167,7 +174,7 @@ export class ActionService extends RequestScopedApiService {
|
|
|
167
174
|
return rootNodes;
|
|
168
175
|
}
|
|
169
176
|
constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider, permissionService){
|
|
170
|
-
super('action', null, cacheManager, utilsService, ActionService.name, true), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "permissionService", void 0), // Custom Methods
|
|
177
|
+
super('action', null, cacheManager, utilsService, ActionService.name, true, 'iam'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "iamConfigService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "permissionService", void 0), // Custom Methods
|
|
171
178
|
_define_property(this, "actionSelectFields", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.dataSourceProvider = dataSourceProvider, this.permissionService = permissionService, this.actionSelectFields = [
|
|
172
179
|
'id',
|
|
173
180
|
'code',
|
|
@@ -26,7 +26,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
import { MultiTenantDataSourceService } from '@flusys/nestjs-shared/modules';
|
|
29
|
-
import {
|
|
29
|
+
import { SYSTEM_MESSAGES } from '@flusys/nestjs-shared/constants';
|
|
30
|
+
import { Inject, Injectable, InternalServerErrorException, Optional, Scope } from '@nestjs/common';
|
|
30
31
|
import { REQUEST } from '@nestjs/core';
|
|
31
32
|
import { Request } from 'express';
|
|
32
33
|
import { PermissionModeHelper } from '../helpers';
|
|
@@ -58,7 +59,7 @@ export class IAMDataSourceService extends MultiTenantDataSourceService {
|
|
|
58
59
|
// Overrides
|
|
59
60
|
async createDataSourceFromConfig(config) {
|
|
60
61
|
const entities = await this.getIAMEntities();
|
|
61
|
-
return super.createDataSourceFromConfig(config, entities);
|
|
62
|
+
return await super.createDataSourceFromConfig(config, entities);
|
|
62
63
|
}
|
|
63
64
|
async getSingleDataSource() {
|
|
64
65
|
if (!IAMDataSourceService.singleDataSource) {
|
|
@@ -68,7 +69,10 @@ export class IAMDataSourceService extends MultiTenantDataSourceService {
|
|
|
68
69
|
const lockPromise = (async ()=>{
|
|
69
70
|
const config = this.getDefaultDatabaseConfig();
|
|
70
71
|
if (!config) {
|
|
71
|
-
throw new
|
|
72
|
+
throw new InternalServerErrorException({
|
|
73
|
+
message: 'Default database config is not available',
|
|
74
|
+
messageKey: SYSTEM_MESSAGES.DATABASE_CONFIG_NOT_AVAILABLE
|
|
75
|
+
});
|
|
72
76
|
}
|
|
73
77
|
const ds = await this.createDataSourceFromConfig(config);
|
|
74
78
|
IAMDataSourceService.singleDataSource = ds;
|
|
@@ -108,7 +112,7 @@ export class IAMDataSourceService extends MultiTenantDataSourceService {
|
|
|
108
112
|
}
|
|
109
113
|
}
|
|
110
114
|
constructor(configService, request){
|
|
111
|
-
super(IAMDataSourceService.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0),
|
|
115
|
+
super(IAMDataSourceService.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), this.configService = configService;
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
// Override parent's static properties to have IAM-specific cache
|