@flusys/nestjs-iam 1.1.0-beta → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +285 -115
- package/cjs/controllers/action.controller.js +45 -2
- package/cjs/controllers/company-action-permission.controller.js +16 -10
- package/cjs/controllers/my-permission.controller.js +7 -3
- package/cjs/controllers/role-permission.controller.js +35 -17
- package/cjs/controllers/role.controller.js +46 -3
- package/cjs/controllers/user-action-permission.controller.js +26 -11
- package/cjs/dtos/action.dto.js +0 -27
- package/cjs/dtos/permission.dto.js +117 -27
- package/cjs/dtos/role.dto.js +0 -27
- package/cjs/entities/permission-base.entity.js +0 -12
- package/cjs/helpers/company-access.helper.js +19 -0
- package/cjs/helpers/index.js +1 -1
- package/cjs/interfaces/iam-module-options.interface.js +0 -14
- package/cjs/interfaces/index.js +0 -1
- package/cjs/modules/iam.module.js +50 -102
- package/cjs/services/action.service.js +30 -41
- package/cjs/services/iam-config.service.js +2 -5
- package/cjs/services/{iam-datasource.provider.js → iam-datasource.service.js} +33 -36
- package/cjs/services/index.js +1 -1
- package/cjs/services/permission-cache.service.js +31 -61
- package/cjs/services/permission.service.js +160 -188
- package/cjs/services/role.service.js +8 -8
- package/cjs/types/logic-node.type.js +0 -24
- package/controllers/company-action-permission.controller.d.ts +3 -3
- package/controllers/my-permission.controller.d.ts +2 -2
- package/controllers/role-permission.controller.d.ts +7 -5
- package/controllers/user-action-permission.controller.d.ts +6 -4
- package/dtos/action.dto.d.ts +0 -7
- package/dtos/permission.dto.d.ts +4 -0
- package/dtos/role.dto.d.ts +0 -7
- package/entities/permission-base.entity.d.ts +0 -4
- package/fesm/controllers/action.controller.js +47 -4
- package/fesm/controllers/company-action-permission.controller.js +18 -12
- package/fesm/controllers/index.js +1 -1
- package/fesm/controllers/my-permission.controller.js +7 -3
- package/fesm/controllers/role-permission.controller.js +37 -19
- package/fesm/controllers/role.controller.js +45 -2
- package/fesm/controllers/user-action-permission.controller.js +28 -13
- package/fesm/dtos/action.dto.js +0 -24
- package/fesm/dtos/permission.dto.js +117 -29
- package/fesm/dtos/role.dto.js +0 -24
- package/fesm/entities/permission-base.entity.js +0 -12
- package/fesm/helpers/company-access.helper.js +14 -0
- package/fesm/helpers/index.js +1 -1
- package/fesm/interfaces/iam-module-options.interface.js +3 -1
- package/fesm/interfaces/index.js +0 -1
- package/fesm/modules/iam.module.js +52 -104
- package/fesm/services/action.service.js +32 -43
- package/fesm/services/iam-config.service.js +2 -5
- package/fesm/services/{iam-datasource.provider.js → iam-datasource.service.js} +31 -34
- package/fesm/services/index.js +1 -1
- package/fesm/services/permission-cache.service.js +31 -61
- package/fesm/services/permission.service.js +161 -189
- package/fesm/services/role.service.js +8 -8
- package/fesm/types/logic-node.type.js +1 -10
- package/helpers/company-access.helper.d.ts +3 -0
- package/helpers/index.d.ts +1 -1
- package/interfaces/iam-module-options.interface.d.ts +9 -1
- package/interfaces/index.d.ts +0 -1
- package/modules/iam.module.d.ts +2 -2
- package/package.json +3 -3
- package/services/action.service.d.ts +6 -4
- package/services/iam-config.service.d.ts +2 -2
- package/services/{iam-datasource.provider.d.ts → iam-datasource.service.d.ts} +4 -5
- package/services/index.d.ts +1 -1
- package/services/permission-cache.service.d.ts +4 -6
- package/services/permission.service.d.ts +8 -4
- package/services/role.service.d.ts +3 -3
- package/types/logic-node.type.d.ts +0 -8
- package/cjs/helpers/permission-evaluator.helper.js +0 -175
- package/cjs/interfaces/iam-module-async-options.interface.js +0 -4
- package/fesm/helpers/permission-evaluator.helper.js +0 -165
- package/fesm/interfaces/iam-module-async-options.interface.js +0 -3
- package/helpers/permission-evaluator.helper.d.ts +0 -26
- package/interfaces/iam-module-async-options.interface.d.ts +0 -11
|
@@ -14,7 +14,7 @@ const _common = require("@nestjs/common");
|
|
|
14
14
|
const _typeorm = require("typeorm");
|
|
15
15
|
const _actionentity = require("../entities/action.entity");
|
|
16
16
|
const _iamconfigservice = require("./iam-config.service");
|
|
17
|
-
const
|
|
17
|
+
const _iamdatasourceservice = require("./iam-datasource.service");
|
|
18
18
|
const _permissionservice = require("./permission.service");
|
|
19
19
|
function _define_property(obj, key, value) {
|
|
20
20
|
if (key in obj) {
|
|
@@ -103,55 +103,33 @@ let ActionService = class ActionService extends _classes.RequestScopedApiService
|
|
|
103
103
|
deletedById: entity.deletedById
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
/** Get actions available for permission assignment (filtered by company whitelist) */ async getActionsForPermission(user) {
|
|
108
|
-
await this.ensureRepositoryInitialized();
|
|
106
|
+
requireUser(user, methodName) {
|
|
109
107
|
if (!user) {
|
|
110
|
-
throw new
|
|
108
|
+
throw new _common.BadRequestException(`User is required for ${methodName}`);
|
|
111
109
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
'permissionLogic',
|
|
119
|
-
'isActive',
|
|
120
|
-
'parentId',
|
|
121
|
-
'serial'
|
|
122
|
-
];
|
|
123
|
-
const enableCompanyFeature = this.iamConfigService.isCompanyFeatureEnabled();
|
|
124
|
-
if (enableCompanyFeature && user.companyId) {
|
|
110
|
+
}
|
|
111
|
+
/** Get actions available for permission assignment (filtered by company whitelist) */ async getActionsForPermission(user) {
|
|
112
|
+
await this.ensureRepositoryInitialized();
|
|
113
|
+
this.requireUser(user, 'getActionsForPermission');
|
|
114
|
+
let whereClause = {};
|
|
115
|
+
if (this.iamConfigService.isCompanyFeatureEnabled() && user.companyId) {
|
|
125
116
|
const companyActionIds = await this.permissionService.getCompanyActionIds(user.companyId);
|
|
126
117
|
if (companyActionIds.length === 0) {
|
|
127
118
|
return [];
|
|
128
119
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
},
|
|
133
|
-
select: selectFields
|
|
134
|
-
});
|
|
135
|
-
return actions.map((action)=>this.convertEntityToResponseDto(action, false));
|
|
120
|
+
whereClause = {
|
|
121
|
+
id: (0, _typeorm.In)(companyActionIds)
|
|
122
|
+
};
|
|
136
123
|
}
|
|
137
124
|
const actions = await this.repository.find({
|
|
138
|
-
|
|
125
|
+
where: whereClause,
|
|
126
|
+
select: this.actionSelectFields
|
|
139
127
|
});
|
|
140
128
|
return actions.map((action)=>this.convertEntityToResponseDto(action, false));
|
|
141
129
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Get actions in hierarchical tree structure
|
|
144
|
-
*
|
|
145
|
-
* @param user - Logged in user info for company filtering
|
|
146
|
-
* @param search - Optional search term (name or code)
|
|
147
|
-
* @param isActive - Optional filter by active status
|
|
148
|
-
* @param withDeleted - Include deleted actions (default: false)
|
|
149
|
-
* @returns Array of root actions with nested children
|
|
150
|
-
*/ async getActionTree(user, search, isActive, withDeleted = false) {
|
|
130
|
+
/** Get actions in hierarchical tree structure */ async getActionTree(user, search, isActive, withDeleted = false) {
|
|
151
131
|
await this.ensureRepositoryInitialized();
|
|
152
|
-
|
|
153
|
-
throw new Error('User is required for getActionTree');
|
|
154
|
-
}
|
|
132
|
+
this.requireUser(user, 'getActionTree');
|
|
155
133
|
const query = this.repository.createQueryBuilder('action');
|
|
156
134
|
if (!withDeleted) {
|
|
157
135
|
query.andWhere('action.deletedAt IS NULL');
|
|
@@ -199,7 +177,18 @@ let ActionService = class ActionService extends _classes.RequestScopedApiService
|
|
|
199
177
|
return rootNodes;
|
|
200
178
|
}
|
|
201
179
|
constructor(cacheManager, utilsService, iamConfigService, dataSourceProvider, permissionService){
|
|
202
|
-
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),
|
|
180
|
+
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
|
|
181
|
+
_define_property(this, "actionSelectFields", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.iamConfigService = iamConfigService, this.dataSourceProvider = dataSourceProvider, this.permissionService = permissionService, this.actionSelectFields = [
|
|
182
|
+
'id',
|
|
183
|
+
'code',
|
|
184
|
+
'name',
|
|
185
|
+
'description',
|
|
186
|
+
'actionType',
|
|
187
|
+
'permissionLogic',
|
|
188
|
+
'isActive',
|
|
189
|
+
'parentId',
|
|
190
|
+
'serial'
|
|
191
|
+
];
|
|
203
192
|
}
|
|
204
193
|
};
|
|
205
194
|
ActionService = _ts_decorate([
|
|
@@ -209,14 +198,14 @@ ActionService = _ts_decorate([
|
|
|
209
198
|
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
210
199
|
_ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
|
|
211
200
|
_ts_param(2, (0, _common.Inject)(_iamconfigservice.IAMConfigService)),
|
|
212
|
-
_ts_param(3, (0, _common.Inject)(
|
|
201
|
+
_ts_param(3, (0, _common.Inject)(_iamdatasourceservice.IAMDataSourceService)),
|
|
213
202
|
_ts_param(4, (0, _common.Inject)(_permissionservice.PermissionService)),
|
|
214
203
|
_ts_metadata("design:type", Function),
|
|
215
204
|
_ts_metadata("design:paramtypes", [
|
|
216
205
|
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
217
206
|
typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
|
|
218
207
|
typeof _iamconfigservice.IAMConfigService === "undefined" ? Object : _iamconfigservice.IAMConfigService,
|
|
219
|
-
typeof
|
|
208
|
+
typeof _iamdatasourceservice.IAMDataSourceService === "undefined" ? Object : _iamdatasourceservice.IAMDataSourceService,
|
|
220
209
|
typeof _permissionservice.PermissionService === "undefined" ? Object : _permissionservice.PermissionService
|
|
221
210
|
])
|
|
222
211
|
], ActionService);
|
|
@@ -48,12 +48,9 @@ let IAMConfigService = class IAMConfigService {
|
|
|
48
48
|
isMultiTenant() {
|
|
49
49
|
return this.getDatabaseMode() === 'multi-tenant';
|
|
50
50
|
}
|
|
51
|
-
//
|
|
52
|
-
getEnableCompanyFeature() {
|
|
53
|
-
return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
54
|
-
}
|
|
51
|
+
// Feature Flags
|
|
55
52
|
isCompanyFeatureEnabled() {
|
|
56
|
-
return this.
|
|
53
|
+
return this.options.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
57
54
|
}
|
|
58
55
|
// Permission Mode
|
|
59
56
|
getPermissionMode() {
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
Object.defineProperty(exports, "
|
|
5
|
+
Object.defineProperty(exports, "IAMDataSourceService", {
|
|
6
6
|
enumerable: true,
|
|
7
7
|
get: function() {
|
|
8
|
-
return
|
|
8
|
+
return IAMDataSourceService;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _modules = require("@flusys/nestjs-shared/modules");
|
|
12
12
|
const _common = require("@nestjs/common");
|
|
13
13
|
const _core = require("@nestjs/core");
|
|
14
14
|
const _express = require("express");
|
|
15
|
-
const
|
|
16
|
-
const
|
|
15
|
+
const _helpers = require("../helpers");
|
|
16
|
+
const _iamconfigservice = require("./iam-config.service");
|
|
17
17
|
function _define_property(obj, key, value) {
|
|
18
18
|
if (key in obj) {
|
|
19
19
|
Object.defineProperty(obj, key, {
|
|
@@ -82,7 +82,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
82
82
|
decorator(target, key, paramIndex);
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
-
let
|
|
85
|
+
let IAMDataSourceService = class IAMDataSourceService extends _modules.MultiTenantDataSourceService {
|
|
86
86
|
// Factory Methods
|
|
87
87
|
static buildParentOptions(options) {
|
|
88
88
|
return {
|
|
@@ -93,20 +93,17 @@ let IAMDataSourceProvider = class IAMDataSourceProvider extends _modules.MultiTe
|
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
// Feature Flags
|
|
96
|
-
getEnableCompanyFeature() {
|
|
97
|
-
return this.iamOptions.bootstrapAppConfig?.enableCompanyFeature ?? false;
|
|
98
|
-
}
|
|
99
96
|
getEnableCompanyFeatureForTenant(tenant) {
|
|
100
|
-
return tenant?.enableCompanyFeature ?? this.
|
|
97
|
+
return tenant?.enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
|
|
101
98
|
}
|
|
102
99
|
getEnableCompanyFeatureForCurrentTenant() {
|
|
103
100
|
return this.getEnableCompanyFeatureForTenant(this.getCurrentTenant() ?? undefined);
|
|
104
101
|
}
|
|
105
102
|
// Entity Management
|
|
106
103
|
async getIAMEntities() {
|
|
107
|
-
const {
|
|
104
|
+
const { getIAMEntitiesByConfig } = await Promise.resolve().then(()=>/*#__PURE__*/ _interop_require_wildcard(require("../entities")));
|
|
108
105
|
const enableCompanyFeature = this.getEnableCompanyFeatureForCurrentTenant();
|
|
109
|
-
const permissionMode = this.
|
|
106
|
+
const permissionMode = _helpers.PermissionModeHelper.toString(this.configService.getPermissionMode());
|
|
110
107
|
return getIAMEntitiesByConfig(enableCompanyFeature, permissionMode);
|
|
111
108
|
}
|
|
112
109
|
// Overrides
|
|
@@ -115,9 +112,9 @@ let IAMDataSourceProvider = class IAMDataSourceProvider extends _modules.MultiTe
|
|
|
115
112
|
return super.createDataSourceFromConfig(config, entities);
|
|
116
113
|
}
|
|
117
114
|
async getSingleDataSource() {
|
|
118
|
-
if (!
|
|
119
|
-
if (
|
|
120
|
-
return
|
|
115
|
+
if (!IAMDataSourceService.singleDataSource) {
|
|
116
|
+
if (IAMDataSourceService.singleConnectionLock) {
|
|
117
|
+
return IAMDataSourceService.singleConnectionLock;
|
|
121
118
|
}
|
|
122
119
|
const lockPromise = (async ()=>{
|
|
123
120
|
const config = this.getDefaultDatabaseConfig();
|
|
@@ -125,63 +122,63 @@ let IAMDataSourceProvider = class IAMDataSourceProvider extends _modules.MultiTe
|
|
|
125
122
|
throw new Error('Default database config is not available');
|
|
126
123
|
}
|
|
127
124
|
const ds = await this.createDataSourceFromConfig(config);
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
IAMDataSourceService.singleDataSource = ds;
|
|
126
|
+
IAMDataSourceService.initialized = true;
|
|
130
127
|
return ds;
|
|
131
128
|
})();
|
|
132
|
-
|
|
129
|
+
IAMDataSourceService.singleConnectionLock = lockPromise;
|
|
133
130
|
try {
|
|
134
131
|
return await lockPromise;
|
|
135
132
|
} finally{
|
|
136
|
-
|
|
133
|
+
IAMDataSourceService.singleConnectionLock = null;
|
|
137
134
|
}
|
|
138
135
|
}
|
|
139
|
-
return
|
|
136
|
+
return IAMDataSourceService.singleDataSource;
|
|
140
137
|
}
|
|
141
138
|
async getOrCreateTenantConnection(tenant) {
|
|
142
139
|
// Return existing initialized connection from IAM-specific cache
|
|
143
|
-
const existing =
|
|
140
|
+
const existing = IAMDataSourceService.tenantConnections.get(tenant.id);
|
|
144
141
|
if (existing?.isInitialized) {
|
|
145
142
|
return existing;
|
|
146
143
|
}
|
|
147
144
|
// If another request is creating this tenant's connection, wait for it
|
|
148
|
-
const pendingConnection =
|
|
145
|
+
const pendingConnection = IAMDataSourceService.connectionLocks.get(tenant.id);
|
|
149
146
|
if (pendingConnection) {
|
|
150
147
|
return pendingConnection;
|
|
151
148
|
}
|
|
152
149
|
// Create connection with lock to prevent race conditions
|
|
153
150
|
const config = this.buildTenantDatabaseConfig(tenant);
|
|
154
151
|
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
155
|
-
|
|
152
|
+
IAMDataSourceService.connectionLocks.set(tenant.id, connectionPromise);
|
|
156
153
|
try {
|
|
157
154
|
const dataSource = await connectionPromise;
|
|
158
|
-
|
|
155
|
+
IAMDataSourceService.tenantConnections.set(tenant.id, dataSource);
|
|
159
156
|
return dataSource;
|
|
160
157
|
} finally{
|
|
161
|
-
|
|
158
|
+
IAMDataSourceService.connectionLocks.delete(tenant.id);
|
|
162
159
|
}
|
|
163
160
|
}
|
|
164
|
-
constructor(
|
|
165
|
-
super(
|
|
161
|
+
constructor(configService, request){
|
|
162
|
+
super(IAMDataSourceService.buildParentOptions(configService.getOptions()), request), _define_property(this, "configService", void 0), _define_property(this, "logger", void 0), this.configService = configService, this.logger = new _common.Logger(IAMDataSourceService.name);
|
|
166
163
|
}
|
|
167
164
|
};
|
|
168
165
|
// Override parent's static properties to have IAM-specific cache
|
|
169
|
-
_define_property(
|
|
170
|
-
_define_property(
|
|
171
|
-
_define_property(
|
|
172
|
-
_define_property(
|
|
173
|
-
_define_property(
|
|
174
|
-
_define_property(
|
|
175
|
-
|
|
166
|
+
_define_property(IAMDataSourceService, "tenantConnections", new Map());
|
|
167
|
+
_define_property(IAMDataSourceService, "singleDataSource", null);
|
|
168
|
+
_define_property(IAMDataSourceService, "tenantsRegistry", new Map());
|
|
169
|
+
_define_property(IAMDataSourceService, "initialized", false);
|
|
170
|
+
_define_property(IAMDataSourceService, "connectionLocks", new Map());
|
|
171
|
+
_define_property(IAMDataSourceService, "singleConnectionLock", null);
|
|
172
|
+
IAMDataSourceService = _ts_decorate([
|
|
176
173
|
(0, _common.Injectable)({
|
|
177
174
|
scope: _common.Scope.REQUEST
|
|
178
175
|
}),
|
|
179
|
-
_ts_param(0, (0, _common.Inject)(
|
|
176
|
+
_ts_param(0, (0, _common.Inject)(_iamconfigservice.IAMConfigService)),
|
|
180
177
|
_ts_param(1, (0, _common.Optional)()),
|
|
181
178
|
_ts_param(1, (0, _common.Inject)(_core.REQUEST)),
|
|
182
179
|
_ts_metadata("design:type", Function),
|
|
183
180
|
_ts_metadata("design:paramtypes", [
|
|
184
|
-
typeof
|
|
181
|
+
typeof _iamconfigservice.IAMConfigService === "undefined" ? Object : _iamconfigservice.IAMConfigService,
|
|
185
182
|
typeof _express.Request === "undefined" ? Object : _express.Request
|
|
186
183
|
])
|
|
187
|
-
],
|
|
184
|
+
], IAMDataSourceService);
|
package/cjs/services/index.js
CHANGED
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
});
|
|
5
5
|
_export_star(require("./action.service"), exports);
|
|
6
6
|
_export_star(require("./iam-config.service"), exports);
|
|
7
|
-
_export_star(require("./iam-datasource.
|
|
7
|
+
_export_star(require("./iam-datasource.service"), exports);
|
|
8
8
|
_export_star(require("./permission-cache.service"), exports);
|
|
9
9
|
_export_star(require("./permission.service"), exports);
|
|
10
10
|
_export_star(require("./role.service"), exports);
|
|
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "PermissionCacheService", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _nestjsshared = require("@flusys/nestjs-shared");
|
|
12
|
+
const _utils = require("@flusys/nestjs-shared/utils");
|
|
12
13
|
const _common = require("@nestjs/common");
|
|
13
14
|
function _define_property(obj, key, value) {
|
|
14
15
|
if (key in obj) {
|
|
@@ -40,18 +41,17 @@ function _ts_param(paramIndex, decorator) {
|
|
|
40
41
|
let PermissionCacheService = class PermissionCacheService {
|
|
41
42
|
// Cache Key Generation
|
|
42
43
|
generateCacheKey(options) {
|
|
43
|
-
|
|
44
|
-
if (enableCompanyFeature && companyId) {
|
|
45
|
-
return `${this.CACHE_PREFIX}:company:${companyId}:branch:${branchId || 'null'}:user:${userId}`;
|
|
46
|
-
}
|
|
47
|
-
return `${this.CACHE_PREFIX}:user:${userId}`;
|
|
44
|
+
return this.buildCacheKey(this.CACHE_PREFIX, options);
|
|
48
45
|
}
|
|
49
46
|
generateMyPermissionsCacheKey(options) {
|
|
47
|
+
return this.buildCacheKey(this.MY_PERMISSIONS_PREFIX, options);
|
|
48
|
+
}
|
|
49
|
+
buildCacheKey(prefix, options) {
|
|
50
50
|
const { userId, companyId, branchId, enableCompanyFeature } = options;
|
|
51
51
|
if (enableCompanyFeature && companyId) {
|
|
52
|
-
return `${
|
|
52
|
+
return `${prefix}:company:${companyId}:branch:${branchId || 'null'}:user:${userId}`;
|
|
53
53
|
}
|
|
54
|
-
return `${
|
|
54
|
+
return `${prefix}:user:${userId}`;
|
|
55
55
|
}
|
|
56
56
|
// Cache Operations
|
|
57
57
|
async setPermissions(options, permissions) {
|
|
@@ -60,20 +60,11 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
60
60
|
await this.cacheManager.set(key, permissions, this.TTL);
|
|
61
61
|
this.logger.debug(`Cached ${permissions.length} permissions for key: ${key}`);
|
|
62
62
|
} catch (error) {
|
|
63
|
-
|
|
63
|
+
const errorMessage = _utils.ErrorHandler.getErrorMessage(error);
|
|
64
|
+
this.logger.error(`Failed to cache permissions: ${errorMessage}`);
|
|
64
65
|
// Don't throw - cache failure shouldn't break the operation
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
async getPermissions(options) {
|
|
68
|
-
try {
|
|
69
|
-
const key = this.generateCacheKey(options);
|
|
70
|
-
const result = await this.cacheManager.get(key);
|
|
71
|
-
return result || null;
|
|
72
|
-
} catch (error) {
|
|
73
|
-
this.logger.error(`Failed to get permissions from cache: ${error}`);
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
68
|
// My-Permissions Cache Operations
|
|
78
69
|
async setMyPermissions(options, data) {
|
|
79
70
|
try {
|
|
@@ -81,7 +72,8 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
81
72
|
await this.cacheManager.set(key, data, this.TTL);
|
|
82
73
|
this.logger.debug(`Cached my-permissions for key: ${key} (${data.frontendActions.length} frontend, ${data.backendCodes.length} backend)`);
|
|
83
74
|
} catch (error) {
|
|
84
|
-
|
|
75
|
+
const errorMessage = _utils.ErrorHandler.getErrorMessage(error);
|
|
76
|
+
this.logger.error(`Failed to cache my-permissions: ${errorMessage}`);
|
|
85
77
|
}
|
|
86
78
|
}
|
|
87
79
|
async getMyPermissions(options) {
|
|
@@ -93,28 +85,35 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
93
85
|
}
|
|
94
86
|
return result || null;
|
|
95
87
|
} catch (error) {
|
|
96
|
-
|
|
88
|
+
const errorMessage = _utils.ErrorHandler.getErrorMessage(error);
|
|
89
|
+
this.logger.error(`Failed to get my-permissions from cache: ${errorMessage}`);
|
|
97
90
|
return null;
|
|
98
91
|
}
|
|
99
92
|
}
|
|
100
|
-
// Action Code Cache Operations
|
|
101
|
-
|
|
93
|
+
// Action Code Cache Operations (tenant-aware for multi-tenant mode)
|
|
94
|
+
/** Generate tenant-aware cache key for action codes */ generateActionCodeCacheKey(tenantId) {
|
|
95
|
+
if (tenantId) {
|
|
96
|
+
return `${this.ACTION_CODE_PREFIX}:tenant:${tenantId}:map`;
|
|
97
|
+
}
|
|
98
|
+
return `${this.ACTION_CODE_PREFIX}:map`;
|
|
99
|
+
}
|
|
100
|
+
async setActionCodeMap(codeToIdMap, tenantId) {
|
|
102
101
|
try {
|
|
103
|
-
const key =
|
|
102
|
+
const key = this.generateActionCodeCacheKey(tenantId);
|
|
104
103
|
await this.cacheManager.set(key, codeToIdMap, this.ACTION_CODE_TTL);
|
|
105
|
-
this.logger.debug(`Cached ${Object.keys(codeToIdMap).length} action code mappings`);
|
|
104
|
+
this.logger.debug(`Cached ${Object.keys(codeToIdMap).length} action code mappings${tenantId ? ` for tenant ${tenantId}` : ''}`);
|
|
106
105
|
} catch (error) {
|
|
107
|
-
|
|
106
|
+
const errorMessage = _utils.ErrorHandler.getErrorMessage(error);
|
|
107
|
+
this.logger.error(`Failed to cache action code map: ${errorMessage}`);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
async getActionIdsByCodes(codes) {
|
|
110
|
+
async getActionIdsByCodes(codes, tenantId) {
|
|
111
111
|
try {
|
|
112
|
-
const key =
|
|
112
|
+
const key = this.generateActionCodeCacheKey(tenantId);
|
|
113
113
|
const fullMap = await this.cacheManager.get(key);
|
|
114
114
|
if (!fullMap) {
|
|
115
115
|
return null;
|
|
116
116
|
}
|
|
117
|
-
// Return only requested codes
|
|
118
117
|
const result = {};
|
|
119
118
|
for (const code of codes){
|
|
120
119
|
if (fullMap[code]) {
|
|
@@ -123,19 +122,11 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
123
122
|
}
|
|
124
123
|
return Object.keys(result).length > 0 ? result : null;
|
|
125
124
|
} catch (error) {
|
|
126
|
-
|
|
125
|
+
const errorMessage = _utils.ErrorHandler.getErrorMessage(error);
|
|
126
|
+
this.logger.error(`Failed to get action IDs from cache: ${errorMessage}`);
|
|
127
127
|
return null;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
-
async invalidateActionCodeCache() {
|
|
131
|
-
try {
|
|
132
|
-
const key = `${this.ACTION_CODE_PREFIX}:map`;
|
|
133
|
-
await this.cacheManager.del(key);
|
|
134
|
-
this.logger.debug('Invalidated action code cache');
|
|
135
|
-
} catch (error) {
|
|
136
|
-
this.logger.warn(`Failed to invalidate action code cache: ${error}`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
130
|
// Cache Invalidation
|
|
140
131
|
async invalidateUser(userId, companyId, branchIds) {
|
|
141
132
|
try {
|
|
@@ -145,10 +136,7 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
145
136
|
// My-permissions cache (full response) - user-based key
|
|
146
137
|
`${this.MY_PERMISSIONS_PREFIX}:user:${userId}`
|
|
147
138
|
];
|
|
148
|
-
// Add company-based keys if companyId provided
|
|
149
139
|
if (companyId) {
|
|
150
|
-
// If branchIds provided, invalidate all specified branches
|
|
151
|
-
// Otherwise, invalidate only null branch (company-wide)
|
|
152
140
|
const branches = branchIds?.length ? branchIds : [
|
|
153
141
|
null
|
|
154
142
|
];
|
|
@@ -156,18 +144,17 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
156
144
|
keysToDelete.push(`${this.CACHE_PREFIX}:company:${companyId}:branch:${branchId || 'null'}:user:${userId}`, `${this.MY_PERMISSIONS_PREFIX}:company:${companyId}:branch:${branchId || 'null'}:user:${userId}`);
|
|
157
145
|
}
|
|
158
146
|
}
|
|
159
|
-
// Parallel deletion for better performance
|
|
160
147
|
await Promise.all(keysToDelete.map((key)=>this.cacheManager.del(key)));
|
|
161
148
|
this.logger.debug(`Invalidated ${keysToDelete.length} cache keys for user ${userId}`);
|
|
162
149
|
} catch (error) {
|
|
163
|
-
|
|
150
|
+
const errorMessage = _utils.ErrorHandler.getErrorMessage(error);
|
|
151
|
+
this.logger.warn(`Failed to invalidate user cache for ${userId}: ${errorMessage}`);
|
|
164
152
|
}
|
|
165
153
|
}
|
|
166
154
|
async invalidateUsers(userIds, companyId, branchIds) {
|
|
167
155
|
if (userIds.length === 0) {
|
|
168
156
|
return 0;
|
|
169
157
|
}
|
|
170
|
-
// Parallel invalidation for better performance
|
|
171
158
|
const results = await Promise.allSettled(userIds.map((userId)=>this.invalidateUser(userId, companyId, branchIds)));
|
|
172
159
|
const successCount = results.filter((r)=>r.status === 'fulfilled').length;
|
|
173
160
|
const failedCount = results.filter((r)=>r.status === 'rejected').length;
|
|
@@ -179,13 +166,6 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
179
166
|
}
|
|
180
167
|
return successCount;
|
|
181
168
|
}
|
|
182
|
-
/** Invalidate cache for all users in company (requires userIds via invalidateUsers) */ async invalidateCompany(companyId) {
|
|
183
|
-
// Note: HybridCache doesn't support pattern matching (keys() method)
|
|
184
|
-
// Company-wide invalidation requires passing individual user IDs
|
|
185
|
-
// This is a placeholder that logs a warning
|
|
186
|
-
this.logger.warn(`invalidateCompany called for ${companyId}, but pattern matching is not supported. ` + `Use invalidateUsers() with specific user IDs instead.`);
|
|
187
|
-
return 0;
|
|
188
|
-
}
|
|
189
169
|
async invalidateRole(roleId, userIds, companyId, branchIds) {
|
|
190
170
|
if (userIds.length === 0) {
|
|
191
171
|
this.logger.debug(`No users found for role ${roleId}`);
|
|
@@ -197,16 +177,6 @@ let PermissionCacheService = class PermissionCacheService {
|
|
|
197
177
|
}
|
|
198
178
|
return count;
|
|
199
179
|
}
|
|
200
|
-
// Administrative Operations
|
|
201
|
-
/** Clear all permission caches (memory and redis) */ async clearAll() {
|
|
202
|
-
try {
|
|
203
|
-
await this.cacheManager.reset(); // Clear memory cache
|
|
204
|
-
await this.cacheManager.resetL2(); // Clear redis cache
|
|
205
|
-
this.logger.warn('Cleared all cache entries (memory and redis)');
|
|
206
|
-
} catch (error) {
|
|
207
|
-
this.logger.error(`Failed to clear all caches: ${error}`);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
180
|
constructor(cacheManager){
|
|
211
181
|
_define_property(this, "cacheManager", void 0);
|
|
212
182
|
_define_property(this, "logger", void 0);
|