@nest-omni/core 4.1.3-11 → 4.1.3-12
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/audit/audit.module.js +17 -0
- package/audit/controllers/audit.controller.d.ts +64 -0
- package/audit/controllers/audit.controller.js +50 -0
- package/audit/decorators/audit-action.decorator.d.ts +74 -0
- package/audit/decorators/audit-action.decorator.js +42 -0
- package/audit/decorators/entity-audit.decorator.d.ts +10 -1
- package/audit/decorators/entity-audit.decorator.js +34 -16
- package/audit/decorators/index.d.ts +1 -0
- package/audit/decorators/index.js +1 -0
- package/audit/entities/audit-action-summary.entity.d.ts +23 -0
- package/audit/entities/audit-action-summary.entity.js +101 -0
- package/audit/entities/entity-audit-log.entity.d.ts +3 -0
- package/audit/entities/entity-audit-log.entity.js +25 -2
- package/audit/entities/entity-transaction.entity.d.ts +3 -4
- package/audit/entities/entity-transaction.entity.js +10 -3
- package/audit/entities/index.d.ts +1 -0
- package/audit/entities/index.js +1 -0
- package/audit/entities/manual-operation-log.entity.js +8 -1
- package/audit/enums/audit.enums.d.ts +1 -10
- package/audit/enums/audit.enums.js +7 -17
- package/audit/index.d.ts +2 -1
- package/audit/index.js +5 -1
- package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
- package/audit/interceptors/audit-action.interceptor.js +215 -0
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +10 -5
- package/audit/services/audit-action.service.d.ts +141 -0
- package/audit/services/audit-action.service.js +244 -0
- package/audit/services/audit-context.service.d.ts +82 -0
- package/audit/services/audit-context.service.js +170 -0
- package/audit/services/entity-audit.service.d.ts +104 -3
- package/audit/services/entity-audit.service.js +306 -9
- package/audit/services/index.d.ts +1 -0
- package/audit/services/index.js +1 -0
- package/audit/services/manual-audit-log.service.d.ts +24 -23
- package/audit/services/manual-audit-log.service.js +32 -53
- package/audit/services/operation-description.service.d.ts +13 -3
- package/audit/services/operation-description.service.js +161 -24
- package/audit/services/transaction-audit.service.js +3 -3
- package/audit/subscribers/entity-audit.subscriber.d.ts +4 -0
- package/audit/subscribers/entity-audit.subscriber.js +47 -0
- package/file-upload/controllers/file-access.controller.d.ts +23 -0
- package/file-upload/controllers/file-access.controller.js +128 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +44 -0
- package/file-upload/decorators/csv-data.decorator.js +131 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +44 -0
- package/file-upload/decorators/excel-data.decorator.js +125 -0
- package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
- package/file-upload/decorators/file-upload.decorator.js +172 -0
- package/file-upload/decorators/index.d.ts +4 -0
- package/file-upload/decorators/index.js +20 -0
- package/file-upload/decorators/process.decorator.d.ts +40 -0
- package/file-upload/decorators/process.decorator.js +52 -0
- package/file-upload/dto/create-file.dto.d.ts +24 -0
- package/file-upload/dto/create-file.dto.js +112 -0
- package/file-upload/dto/find-files.dto.d.ts +15 -0
- package/file-upload/dto/find-files.dto.js +76 -0
- package/file-upload/dto/index.d.ts +4 -0
- package/file-upload/dto/index.js +20 -0
- package/file-upload/dto/pagination.dto.d.ts +7 -0
- package/file-upload/dto/pagination.dto.js +39 -0
- package/file-upload/dto/update-file.dto.d.ts +16 -0
- package/file-upload/dto/update-file.dto.js +71 -0
- package/file-upload/entities/file-metadata.entity.d.ts +22 -0
- package/file-upload/entities/file-metadata.entity.js +84 -0
- package/file-upload/entities/file.entity.d.ts +129 -0
- package/file-upload/entities/file.entity.js +384 -0
- package/file-upload/entities/index.d.ts +2 -0
- package/file-upload/entities/index.js +18 -0
- package/file-upload/enums/file-type.enum.d.ts +72 -0
- package/file-upload/enums/file-type.enum.js +212 -0
- package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
- package/file-upload/exceptions/file-upload.exception.js +120 -0
- package/file-upload/exceptions/index.d.ts +1 -0
- package/file-upload/exceptions/index.js +17 -0
- package/file-upload/file-upload.module.d.ts +89 -0
- package/file-upload/file-upload.module.js +264 -0
- package/file-upload/index.d.ts +26 -0
- package/file-upload/index.js +59 -0
- package/file-upload/interceptors/file-upload.interceptor.d.ts +48 -0
- package/file-upload/interceptors/file-upload.interceptor.js +434 -0
- package/file-upload/interceptors/index.d.ts +1 -0
- package/file-upload/interceptors/index.js +17 -0
- package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
- package/file-upload/interfaces/custom-file-type.interface.js +2 -0
- package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
- package/file-upload/interfaces/file-buffer.interface.js +2 -0
- package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
- package/file-upload/interfaces/file-entity.interface.js +28 -0
- package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
- package/file-upload/interfaces/file-metadata.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +117 -0
- package/file-upload/interfaces/file-upload-options.interface.js +2 -0
- package/file-upload/interfaces/index.d.ts +7 -0
- package/file-upload/interfaces/index.js +24 -0
- package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
- package/file-upload/interfaces/storage-provider.interface.js +2 -0
- package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
- package/file-upload/interfaces/upload-options.interface.js +2 -0
- package/file-upload/providers/index.d.ts +2 -0
- package/file-upload/providers/index.js +18 -0
- package/file-upload/providers/local-storage.provider.d.ts +98 -0
- package/file-upload/providers/local-storage.provider.js +484 -0
- package/file-upload/providers/s3-storage.provider.d.ts +87 -0
- package/file-upload/providers/s3-storage.provider.js +455 -0
- package/file-upload/services/file-signature-validator.service.d.ts +118 -0
- package/file-upload/services/file-signature-validator.service.js +376 -0
- package/file-upload/services/file.service.d.ts +190 -0
- package/file-upload/services/file.service.js +609 -0
- package/file-upload/services/index.d.ts +4 -0
- package/file-upload/services/index.js +20 -0
- package/file-upload/services/malicious-file-detector.service.d.ts +274 -0
- package/file-upload/services/malicious-file-detector.service.js +1035 -0
- package/file-upload/services/mime-registry.service.d.ts +47 -0
- package/file-upload/services/mime-registry.service.js +167 -0
- package/file-upload/utils/checksum.util.d.ts +28 -0
- package/file-upload/utils/checksum.util.js +65 -0
- package/file-upload/utils/dynamic-import.util.d.ts +50 -0
- package/file-upload/utils/dynamic-import.util.js +144 -0
- package/file-upload/utils/filename.util.d.ts +59 -0
- package/file-upload/utils/filename.util.js +184 -0
- package/file-upload/utils/filepath.util.d.ts +70 -0
- package/file-upload/utils/filepath.util.js +152 -0
- package/file-upload/utils/index.d.ts +4 -0
- package/file-upload/utils/index.js +20 -0
- package/index.d.ts +3 -1
- package/index.js +4 -1
- package/package.json +4 -5
- package/setup/bootstrap.setup.d.ts +1 -0
- package/setup/bootstrap.setup.js +1 -0
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +0 -12
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- package/transaction/__tests__/mocks.d.ts +9 -0
- package/transaction/__tests__/mocks.js +33 -0
- package/transaction/base-service-transaction.d.ts +99 -0
- package/transaction/base-service-transaction.js +286 -0
- package/transaction/cls-compatibility.service.d.ts +55 -0
- package/transaction/cls-compatibility.service.js +127 -0
- package/transaction/data-source-registry.d.ts +91 -0
- package/transaction/data-source-registry.js +349 -0
- package/transaction/database-adapter.d.ts +44 -0
- package/transaction/database-adapter.js +240 -0
- package/transaction/decorators/entity-datasource.decorator.d.ts +62 -0
- package/transaction/decorators/entity-datasource.decorator.js +105 -0
- package/transaction/index.d.ts +14 -0
- package/transaction/index.js +57 -0
- package/transaction/logging-transactional.interceptor.d.ts +18 -0
- package/transaction/logging-transactional.interceptor.js +163 -0
- package/transaction/transaction-context.service.d.ts +137 -0
- package/transaction/transaction-context.service.js +411 -0
- package/transaction/transaction-manager.d.ts +230 -0
- package/transaction/transaction-manager.js +1001 -0
- package/transaction/transaction-synchronization.d.ts +171 -0
- package/transaction/transaction-synchronization.js +380 -0
- package/transaction/transaction.errors.d.ts +91 -0
- package/transaction/transaction.errors.js +206 -0
- package/transaction/transaction.module.d.ts +30 -0
- package/transaction/transaction.module.js +98 -0
- package/transaction/transactional.decorator.d.ts +82 -0
- package/transaction/transactional.decorator.js +319 -0
- package/transaction/typeorm-module-wrapper.d.ts +96 -0
- package/transaction/typeorm-module-wrapper.js +197 -0
- package/validators/file-mimetype.validator.d.ts +0 -2
- package/validators/file-mimetype.validator.js +4 -6
- package/validators/is-exists.validator.d.ts +2 -5
- package/validators/is-exists.validator.js +4 -6
- package/validators/is-unique.validator.d.ts +2 -5
- package/validators/is-unique.validator.js +6 -11
- package/shared/services/validator.service.d.ts +0 -3
- package/shared/services/validator.service.js +0 -20
- /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
|
@@ -20,7 +20,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
20
20
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
|
-
var ManualAuditLogService_1;
|
|
24
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
24
|
exports.ManualAuditLogService = void 0;
|
|
26
25
|
const common_1 = require("@nestjs/common");
|
|
@@ -33,19 +32,18 @@ const crypto_1 = require("crypto");
|
|
|
33
32
|
/**
|
|
34
33
|
* 手动审计日志服务
|
|
35
34
|
*
|
|
36
|
-
*
|
|
35
|
+
* 提供标准的依赖注入方式记录操作日志
|
|
36
|
+
* @deprecated 静态方法已废弃,请使用依赖注入方式
|
|
37
37
|
*/
|
|
38
|
-
let ManualAuditLogService =
|
|
38
|
+
let ManualAuditLogService = class ManualAuditLogService {
|
|
39
39
|
constructor(manualLogRepository, transactionRepository, contextService, dataSource) {
|
|
40
40
|
this.manualLogRepository = manualLogRepository;
|
|
41
41
|
this.transactionRepository = transactionRepository;
|
|
42
42
|
this.contextService = contextService;
|
|
43
43
|
this.dataSource = dataSource;
|
|
44
|
-
// 设置静态实例
|
|
45
|
-
ManualAuditLogService_1.instance = this;
|
|
46
44
|
}
|
|
47
45
|
/**
|
|
48
|
-
*
|
|
46
|
+
* 记录操作日志
|
|
49
47
|
*
|
|
50
48
|
* @description
|
|
51
49
|
* 支持三种记录模式:
|
|
@@ -55,7 +53,7 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
55
53
|
*
|
|
56
54
|
* @example
|
|
57
55
|
* // 模式1:模板键模式
|
|
58
|
-
* await
|
|
56
|
+
* await this.manualAuditLogService.log({
|
|
59
57
|
* templateKey: 'user.login',
|
|
60
58
|
* descriptionParams: {
|
|
61
59
|
* username: 'john.doe',
|
|
@@ -65,13 +63,13 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
65
63
|
*
|
|
66
64
|
* @example
|
|
67
65
|
* // 模式2:直接描述模式(字符串)
|
|
68
|
-
* await
|
|
66
|
+
* await this.manualAuditLogService.log({
|
|
69
67
|
* description: '用户登录系统',
|
|
70
68
|
* });
|
|
71
69
|
*
|
|
72
70
|
* @example
|
|
73
71
|
* // 模式2:直接描述模式(多语言)
|
|
74
|
-
* await
|
|
72
|
+
* await this.manualAuditLogService.log({
|
|
75
73
|
* description: {
|
|
76
74
|
* zh: '用户登录系统',
|
|
77
75
|
* en: 'User logged in',
|
|
@@ -80,7 +78,7 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
80
78
|
*
|
|
81
79
|
* @example
|
|
82
80
|
* // 模式3:内联模板模式
|
|
83
|
-
* await
|
|
81
|
+
* await this.manualAuditLogService.log({
|
|
84
82
|
* descriptionTemplate: {
|
|
85
83
|
* zh: '用户 {username} 在 {time} 登录了系统',
|
|
86
84
|
* en: 'User {username} logged in at {time}',
|
|
@@ -91,12 +89,9 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
91
89
|
* },
|
|
92
90
|
* });
|
|
93
91
|
*/
|
|
94
|
-
|
|
92
|
+
log(options) {
|
|
95
93
|
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
-
|
|
97
|
-
throw new Error('ManualAuditLogService is not initialized. Make sure AuditModule is imported.');
|
|
98
|
-
}
|
|
99
|
-
return ManualAuditLogService_1.instance.logOperation(options);
|
|
94
|
+
return this.logOperation(options);
|
|
100
95
|
});
|
|
101
96
|
}
|
|
102
97
|
/**
|
|
@@ -146,57 +141,48 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
146
141
|
});
|
|
147
142
|
}
|
|
148
143
|
/**
|
|
149
|
-
*
|
|
144
|
+
* 开始事务
|
|
150
145
|
*
|
|
151
146
|
* @example
|
|
152
147
|
* ```typescript
|
|
153
|
-
* const txId = await
|
|
148
|
+
* const txId = await this.manualAuditLogService.beginTransaction('user-123', 'John Doe');
|
|
154
149
|
*
|
|
155
|
-
* await
|
|
150
|
+
* await this.manualAuditLogService.log({
|
|
156
151
|
* templateKey: 'order.create',
|
|
157
152
|
* descriptionParams: { orderId: 'order-1' },
|
|
158
153
|
* transactionId: txId,
|
|
159
154
|
* autoCreateTransaction: false,
|
|
160
155
|
* });
|
|
161
156
|
*
|
|
162
|
-
* await
|
|
157
|
+
* await this.manualAuditLogService.log({
|
|
163
158
|
* templateKey: 'payment.process',
|
|
164
159
|
* descriptionParams: { paymentId: 'pay-1' },
|
|
165
160
|
* transactionId: txId,
|
|
166
161
|
* autoCreateTransaction: false,
|
|
167
162
|
* });
|
|
168
163
|
*
|
|
169
|
-
* await
|
|
164
|
+
* await this.manualAuditLogService.commitTransaction(txId);
|
|
170
165
|
* ```
|
|
171
166
|
*/
|
|
172
|
-
|
|
167
|
+
beginTransaction(userId, username) {
|
|
173
168
|
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
|
|
175
|
-
throw new Error('ManualAuditLogService is not initialized');
|
|
176
|
-
}
|
|
177
|
-
return ManualAuditLogService_1.instance.createTransaction(userId, username);
|
|
169
|
+
return this.createTransaction(userId, username);
|
|
178
170
|
});
|
|
179
171
|
}
|
|
180
172
|
/**
|
|
181
|
-
*
|
|
173
|
+
* 提交事务
|
|
182
174
|
*/
|
|
183
|
-
|
|
175
|
+
commitTransaction(transactionId) {
|
|
184
176
|
return __awaiter(this, void 0, void 0, function* () {
|
|
185
|
-
|
|
186
|
-
throw new Error('ManualAuditLogService is not initialized');
|
|
187
|
-
}
|
|
188
|
-
yield ManualAuditLogService_1.instance.updateTransactionStatus(transactionId, enums_1.TransactionStatus.COMMITTED);
|
|
177
|
+
yield this.updateTransactionStatus(transactionId, enums_1.AuditTransactionStatus.COMMITTED);
|
|
189
178
|
});
|
|
190
179
|
}
|
|
191
180
|
/**
|
|
192
|
-
*
|
|
181
|
+
* 回滚事务
|
|
193
182
|
*/
|
|
194
|
-
|
|
183
|
+
rollbackTransaction(transactionId) {
|
|
195
184
|
return __awaiter(this, void 0, void 0, function* () {
|
|
196
|
-
|
|
197
|
-
throw new Error('ManualAuditLogService is not initialized');
|
|
198
|
-
}
|
|
199
|
-
yield ManualAuditLogService_1.instance.updateTransactionStatus(transactionId, enums_1.TransactionStatus.ROLLED_BACK);
|
|
185
|
+
yield this.updateTransactionStatus(transactionId, enums_1.AuditTransactionStatus.ROLLED_BACK);
|
|
200
186
|
});
|
|
201
187
|
}
|
|
202
188
|
/**
|
|
@@ -210,7 +196,7 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
210
196
|
userId: userId || context.userId || 'system',
|
|
211
197
|
username: username || context.username || 'system',
|
|
212
198
|
requestIp: context.requestIp || 'unknown',
|
|
213
|
-
status: enums_1.
|
|
199
|
+
status: enums_1.AuditTransactionStatus.PENDING,
|
|
214
200
|
entities: [],
|
|
215
201
|
});
|
|
216
202
|
const saved = yield this.transactionRepository.save(transaction);
|
|
@@ -240,7 +226,7 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
240
226
|
* @example
|
|
241
227
|
* ```typescript
|
|
242
228
|
* // 混合使用多种模式
|
|
243
|
-
* await
|
|
229
|
+
* await this.manualAuditLogService.logBatch([
|
|
244
230
|
* {
|
|
245
231
|
* templateKey: 'product.update',
|
|
246
232
|
* descriptionParams: { productId: 'p1', field: 'price' },
|
|
@@ -258,22 +244,18 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
258
244
|
* ]);
|
|
259
245
|
* ```
|
|
260
246
|
*/
|
|
261
|
-
|
|
247
|
+
logBatch(operations, sharedTransactionId) {
|
|
262
248
|
return __awaiter(this, void 0, void 0, function* () {
|
|
263
|
-
if (!ManualAuditLogService_1.instance) {
|
|
264
|
-
throw new Error('ManualAuditLogService is not initialized');
|
|
265
|
-
}
|
|
266
249
|
// 创建共享事务ID
|
|
267
|
-
const transactionId = sharedTransactionId ||
|
|
268
|
-
(yield ManualAuditLogService_1.instance.createTransaction());
|
|
250
|
+
const transactionId = sharedTransactionId || (yield this.createTransaction());
|
|
269
251
|
const results = [];
|
|
270
252
|
for (const operation of operations) {
|
|
271
|
-
const result = yield
|
|
253
|
+
const result = yield this.logOperation(Object.assign(Object.assign({}, operation), { transactionId, autoCreateTransaction: false }));
|
|
272
254
|
results.push(result);
|
|
273
255
|
}
|
|
274
256
|
// 自动提交事务(如果是自动创建的)
|
|
275
257
|
if (!sharedTransactionId) {
|
|
276
|
-
yield
|
|
258
|
+
yield this.updateTransactionStatus(transactionId, enums_1.AuditTransactionStatus.COMMITTED);
|
|
277
259
|
}
|
|
278
260
|
return results;
|
|
279
261
|
});
|
|
@@ -281,13 +263,10 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
281
263
|
/**
|
|
282
264
|
* 查询操作日志
|
|
283
265
|
*/
|
|
284
|
-
|
|
266
|
+
findLogs(options) {
|
|
285
267
|
return __awaiter(this, void 0, void 0, function* () {
|
|
286
|
-
if (!ManualAuditLogService_1.instance) {
|
|
287
|
-
throw new Error('ManualAuditLogService is not initialized');
|
|
288
|
-
}
|
|
289
268
|
const { templateKey, userId, transactionId, startTime, endTime, limit = 100 } = options;
|
|
290
|
-
const query =
|
|
269
|
+
const query = this.manualLogRepository
|
|
291
270
|
.createQueryBuilder('log')
|
|
292
271
|
.orderBy('log.createdAt', 'DESC')
|
|
293
272
|
.take(limit);
|
|
@@ -311,7 +290,7 @@ let ManualAuditLogService = ManualAuditLogService_1 = class ManualAuditLogServic
|
|
|
311
290
|
}
|
|
312
291
|
};
|
|
313
292
|
exports.ManualAuditLogService = ManualAuditLogService;
|
|
314
|
-
exports.ManualAuditLogService = ManualAuditLogService =
|
|
293
|
+
exports.ManualAuditLogService = ManualAuditLogService = __decorate([
|
|
315
294
|
(0, common_1.Injectable)(),
|
|
316
295
|
__param(0, (0, typeorm_1.InjectRepository)(entities_1.ManualOperationLogEntity, 'audit')),
|
|
317
296
|
__param(1, (0, typeorm_1.InjectRepository)(entities_1.EntityTransactionEntity, 'audit')),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Repository } from 'typeorm';
|
|
2
2
|
import { OperationTemplateEntity, EntityTransactionEntity, EntityAuditLogEntity, ManualOperationLogEntity } from '../entities';
|
|
3
3
|
import { ChangeDetail, TransactionDescription } from '../interfaces';
|
|
4
|
+
import { CacheService } from '../../cache';
|
|
4
5
|
/**
|
|
5
6
|
* 操作描述服务
|
|
6
7
|
* 负责根据模板和参数动态生成多语言描述
|
|
@@ -10,8 +11,10 @@ export declare class OperationDescriptionService {
|
|
|
10
11
|
private readonly transactionRepository;
|
|
11
12
|
private readonly auditLogRepository;
|
|
12
13
|
private readonly manualOperationRepository;
|
|
13
|
-
private
|
|
14
|
-
|
|
14
|
+
private readonly cacheService;
|
|
15
|
+
private readonly CACHE_NAMESPACE;
|
|
16
|
+
private readonly CACHE_TTL;
|
|
17
|
+
constructor(templateRepository: Repository<OperationTemplateEntity>, transactionRepository: Repository<EntityTransactionEntity>, auditLogRepository: Repository<EntityAuditLogEntity>, manualOperationRepository: Repository<ManualOperationLogEntity>, cacheService: CacheService);
|
|
15
18
|
/**
|
|
16
19
|
* 动态生成操作名称
|
|
17
20
|
* @param templateKey 模板键
|
|
@@ -63,11 +66,18 @@ export declare class OperationDescriptionService {
|
|
|
63
66
|
*/
|
|
64
67
|
private formatDisplayValue;
|
|
65
68
|
/**
|
|
66
|
-
*
|
|
69
|
+
* 获取操作模板(使用统一缓存服务)
|
|
67
70
|
* @param templateKey 模板键
|
|
68
71
|
* @returns 操作模板
|
|
69
72
|
*/
|
|
70
73
|
private getOperationTemplate;
|
|
74
|
+
/**
|
|
75
|
+
* 获取模板字符串(仅返回模板文本,不填充参数)
|
|
76
|
+
* @param templateKey 模板键
|
|
77
|
+
* @param language 语言
|
|
78
|
+
* @returns 模板字符串
|
|
79
|
+
*/
|
|
80
|
+
getTemplate(templateKey: string, language?: string): Promise<string | null>;
|
|
71
81
|
/**
|
|
72
82
|
* 清除模板缓存
|
|
73
83
|
*/
|
|
@@ -26,18 +26,22 @@ const common_1 = require("@nestjs/common");
|
|
|
26
26
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
27
27
|
const typeorm_2 = require("typeorm");
|
|
28
28
|
const entities_1 = require("../entities");
|
|
29
|
+
const cache_1 = require("../../cache");
|
|
29
30
|
/**
|
|
30
31
|
* 操作描述服务
|
|
31
32
|
* 负责根据模板和参数动态生成多语言描述
|
|
32
33
|
*/
|
|
33
34
|
let OperationDescriptionService = class OperationDescriptionService {
|
|
34
|
-
constructor(templateRepository, transactionRepository, auditLogRepository, manualOperationRepository) {
|
|
35
|
+
constructor(templateRepository, transactionRepository, auditLogRepository, manualOperationRepository, cacheService) {
|
|
35
36
|
this.templateRepository = templateRepository;
|
|
36
37
|
this.transactionRepository = transactionRepository;
|
|
37
38
|
this.auditLogRepository = auditLogRepository;
|
|
38
39
|
this.manualOperationRepository = manualOperationRepository;
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
this.cacheService = cacheService;
|
|
41
|
+
// 缓存命名空间
|
|
42
|
+
this.CACHE_NAMESPACE = 'audit:template';
|
|
43
|
+
// 缓存TTL(30分钟)
|
|
44
|
+
this.CACHE_TTL = 30 * 60 * 1000;
|
|
41
45
|
}
|
|
42
46
|
/**
|
|
43
47
|
* 动态生成操作名称
|
|
@@ -182,14 +186,123 @@ let OperationDescriptionService = class OperationDescriptionService {
|
|
|
182
186
|
*/
|
|
183
187
|
batchGetTransactionDescriptions(transactionIds_1) {
|
|
184
188
|
return __awaiter(this, arguments, void 0, function* (transactionIds, language = 'zh') {
|
|
189
|
+
if (transactionIds.length === 0) {
|
|
190
|
+
return {};
|
|
191
|
+
}
|
|
192
|
+
// 批量查询事务信息
|
|
193
|
+
const transactions = yield this.transactionRepository
|
|
194
|
+
.createQueryBuilder('tx')
|
|
195
|
+
.whereInIds(transactionIds)
|
|
196
|
+
.getMany();
|
|
197
|
+
// 批量查询审计日志
|
|
198
|
+
const auditLogs = yield this.auditLogRepository
|
|
199
|
+
.createQueryBuilder('log')
|
|
200
|
+
.where('log.requestId IN (:...transactionIds)', { transactionIds })
|
|
201
|
+
.orderBy('log.createdAt', 'ASC')
|
|
202
|
+
.getMany();
|
|
203
|
+
// 批量查询手动操作记录
|
|
204
|
+
const manualOperations = yield this.manualOperationRepository
|
|
205
|
+
.createQueryBuilder('op')
|
|
206
|
+
.where('op.transactionId IN (:...transactionIds)', { transactionIds })
|
|
207
|
+
.orderBy('op.createdAt', 'ASC')
|
|
208
|
+
.getMany();
|
|
209
|
+
// 收集所有需要的模板键
|
|
210
|
+
const templateKeys = new Set();
|
|
211
|
+
transactions.forEach(tx => {
|
|
212
|
+
if (tx.operationTemplateKey)
|
|
213
|
+
templateKeys.add(tx.operationTemplateKey);
|
|
214
|
+
});
|
|
215
|
+
auditLogs.forEach(log => {
|
|
216
|
+
if (log.operationTemplateKey)
|
|
217
|
+
templateKeys.add(log.operationTemplateKey);
|
|
218
|
+
});
|
|
219
|
+
manualOperations.forEach(op => {
|
|
220
|
+
if (op.operationTemplateKey)
|
|
221
|
+
templateKeys.add(op.operationTemplateKey);
|
|
222
|
+
});
|
|
223
|
+
// 批量预加载模板
|
|
224
|
+
if (templateKeys.size > 0) {
|
|
225
|
+
yield this.preloadTemplates(Array.from(templateKeys));
|
|
226
|
+
}
|
|
227
|
+
// 按事务ID分组
|
|
228
|
+
const logsByTxId = new Map();
|
|
229
|
+
const opsByTxId = new Map();
|
|
230
|
+
auditLogs.forEach(log => {
|
|
231
|
+
const txId = log.requestId;
|
|
232
|
+
if (!logsByTxId.has(txId))
|
|
233
|
+
logsByTxId.set(txId, []);
|
|
234
|
+
logsByTxId.get(txId).push(log);
|
|
235
|
+
});
|
|
236
|
+
manualOperations.forEach(op => {
|
|
237
|
+
const txId = op.transactionId;
|
|
238
|
+
if (!opsByTxId.has(txId))
|
|
239
|
+
opsByTxId.set(txId, []);
|
|
240
|
+
opsByTxId.get(txId).push(op);
|
|
241
|
+
});
|
|
242
|
+
// 构建结果
|
|
185
243
|
const results = {};
|
|
186
|
-
for (const
|
|
244
|
+
for (const transaction of transactions) {
|
|
187
245
|
try {
|
|
188
|
-
|
|
246
|
+
const txLogs = logsByTxId.get(transaction.id) || [];
|
|
247
|
+
const txOps = opsByTxId.get(transaction.id) || [];
|
|
248
|
+
// 生成操作名称和描述
|
|
249
|
+
let operationName;
|
|
250
|
+
let description;
|
|
251
|
+
if (transaction.operationTemplateKey) {
|
|
252
|
+
operationName = yield this.generateOperationName(transaction.operationTemplateKey, language);
|
|
253
|
+
description = yield this.generateDescription(transaction.operationTemplateKey, transaction.descriptionParams || {}, language);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
const firstLog = txLogs[0];
|
|
257
|
+
if (firstLog && firstLog.operationTemplateKey) {
|
|
258
|
+
operationName = yield this.generateOperationName(firstLog.operationTemplateKey, language);
|
|
259
|
+
description = yield this.generateDescription(firstLog.operationTemplateKey, firstLog.descriptionParams || {}, language);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
operationName = 'Unknown Operation';
|
|
263
|
+
description = transaction.description || 'Unknown operation';
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// 生成变更详情
|
|
267
|
+
const changes = [];
|
|
268
|
+
// 添加实体变更
|
|
269
|
+
for (const log of txLogs) {
|
|
270
|
+
const changeDescription = log.operationTemplateKey
|
|
271
|
+
? yield this.generateDescription(log.operationTemplateKey, log.descriptionParams || {}, language)
|
|
272
|
+
: log.description || '';
|
|
273
|
+
const changeDetails = log.changeDetails
|
|
274
|
+
? yield this.generateChangeDetails(log.changeDetails, language)
|
|
275
|
+
: [];
|
|
276
|
+
changes.push({
|
|
277
|
+
entityName: log.entityType,
|
|
278
|
+
entityId: log.entityId,
|
|
279
|
+
operation: log.operation,
|
|
280
|
+
description: changeDescription,
|
|
281
|
+
details: changeDetails,
|
|
282
|
+
createdAt: log.createdAt,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// 添加手动操作
|
|
286
|
+
for (const manualOp of txOps) {
|
|
287
|
+
const opName = yield this.generateOperationName(manualOp.operationTemplateKey, language);
|
|
288
|
+
const opDescription = yield this.generateDescription(manualOp.operationTemplateKey, manualOp.descriptionParams, language);
|
|
289
|
+
changes.push({
|
|
290
|
+
type: 'manual',
|
|
291
|
+
description: `${opName}: ${opDescription}`,
|
|
292
|
+
details: manualOp.descriptionParams,
|
|
293
|
+
createdAt: manualOp.createdAt,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
// 按时间排序
|
|
297
|
+
changes.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
298
|
+
results[transaction.id] = {
|
|
299
|
+
operationName,
|
|
300
|
+
description,
|
|
301
|
+
changes,
|
|
302
|
+
};
|
|
189
303
|
}
|
|
190
304
|
catch (error) {
|
|
191
|
-
|
|
192
|
-
console.error(`Failed to get description for transaction ${transactionId}:`, error);
|
|
305
|
+
console.error(`Failed to get description for transaction ${transaction.id}:`, error);
|
|
193
306
|
}
|
|
194
307
|
}
|
|
195
308
|
return results;
|
|
@@ -230,32 +343,48 @@ let OperationDescriptionService = class OperationDescriptionService {
|
|
|
230
343
|
return String(value);
|
|
231
344
|
}
|
|
232
345
|
/**
|
|
233
|
-
*
|
|
346
|
+
* 获取操作模板(使用统一缓存服务)
|
|
234
347
|
* @param templateKey 模板键
|
|
235
348
|
* @returns 操作模板
|
|
236
349
|
*/
|
|
237
350
|
getOperationTemplate(templateKey) {
|
|
238
351
|
return __awaiter(this, void 0, void 0, function* () {
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
352
|
+
// 使用统一缓存服务的 getOrSet 方法
|
|
353
|
+
return this.cacheService.getOrSet(templateKey, () => __awaiter(this, void 0, void 0, function* () {
|
|
354
|
+
// 从数据库查询
|
|
355
|
+
const template = yield this.templateRepository.findOne({
|
|
356
|
+
where: { key: templateKey },
|
|
357
|
+
});
|
|
358
|
+
return template;
|
|
359
|
+
}), {
|
|
360
|
+
namespace: this.CACHE_NAMESPACE,
|
|
361
|
+
ttl: this.CACHE_TTL,
|
|
362
|
+
// 只使用内存缓存层,避免序列化开销
|
|
363
|
+
layers: [cache_1.CacheLayer.MEMORY],
|
|
246
364
|
});
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* 获取模板字符串(仅返回模板文本,不填充参数)
|
|
369
|
+
* @param templateKey 模板键
|
|
370
|
+
* @param language 语言
|
|
371
|
+
* @returns 模板字符串
|
|
372
|
+
*/
|
|
373
|
+
getTemplate(templateKey_1) {
|
|
374
|
+
return __awaiter(this, arguments, void 0, function* (templateKey, language = 'zh') {
|
|
375
|
+
const template = yield this.getOperationTemplate(templateKey);
|
|
376
|
+
if (!template) {
|
|
377
|
+
return null;
|
|
250
378
|
}
|
|
251
|
-
return template;
|
|
379
|
+
return template.descriptionTemplates[language] || template.descriptionTemplates['zh'] || null;
|
|
252
380
|
});
|
|
253
381
|
}
|
|
254
382
|
/**
|
|
255
383
|
* 清除模板缓存
|
|
256
384
|
*/
|
|
257
385
|
clearTemplateCache() {
|
|
258
|
-
|
|
386
|
+
// 使用统一缓存服务清除
|
|
387
|
+
this.cacheService.deletePattern(`${this.CACHE_NAMESPACE}:*`, [cache_1.CacheLayer.MEMORY]);
|
|
259
388
|
}
|
|
260
389
|
/**
|
|
261
390
|
* 预加载模板到缓存
|
|
@@ -267,9 +396,16 @@ let OperationDescriptionService = class OperationDescriptionService {
|
|
|
267
396
|
.createQueryBuilder('template')
|
|
268
397
|
.where('template.key IN (:...keys)', { keys: templateKeys })
|
|
269
398
|
.getMany();
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
399
|
+
// 批量设置到缓存
|
|
400
|
+
const cacheItems = templates.map(template => ({
|
|
401
|
+
key: template.key,
|
|
402
|
+
value: template,
|
|
403
|
+
}));
|
|
404
|
+
yield this.cacheService.mset(cacheItems, {
|
|
405
|
+
namespace: this.CACHE_NAMESPACE,
|
|
406
|
+
ttl: this.CACHE_TTL,
|
|
407
|
+
layers: [cache_1.CacheLayer.MEMORY],
|
|
408
|
+
});
|
|
273
409
|
});
|
|
274
410
|
}
|
|
275
411
|
};
|
|
@@ -283,5 +419,6 @@ exports.OperationDescriptionService = OperationDescriptionService = __decorate([
|
|
|
283
419
|
__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
284
420
|
typeorm_2.Repository,
|
|
285
421
|
typeorm_2.Repository,
|
|
286
|
-
typeorm_2.Repository
|
|
422
|
+
typeorm_2.Repository,
|
|
423
|
+
cache_1.CacheService])
|
|
287
424
|
], OperationDescriptionService);
|
|
@@ -48,7 +48,7 @@ let TransactionAuditService = class TransactionAuditService {
|
|
|
48
48
|
const context = yield this.contextService.getCurrentContext();
|
|
49
49
|
const transaction = this.transactionRepository.create({
|
|
50
50
|
description,
|
|
51
|
-
status: enums_1.
|
|
51
|
+
status: enums_1.AuditTransactionStatus.PENDING,
|
|
52
52
|
entities: [],
|
|
53
53
|
userId: context.userId,
|
|
54
54
|
username: context.username,
|
|
@@ -72,7 +72,7 @@ let TransactionAuditService = class TransactionAuditService {
|
|
|
72
72
|
if (!transaction) {
|
|
73
73
|
throw new Error(`Transaction not found: ${transactionId}`);
|
|
74
74
|
}
|
|
75
|
-
transaction.status = enums_1.
|
|
75
|
+
transaction.status = enums_1.AuditTransactionStatus.COMMITTED;
|
|
76
76
|
yield this.transactionRepository.save(transaction);
|
|
77
77
|
});
|
|
78
78
|
}
|
|
@@ -89,7 +89,7 @@ let TransactionAuditService = class TransactionAuditService {
|
|
|
89
89
|
}
|
|
90
90
|
// 执行回滚操作
|
|
91
91
|
yield this.performRollback(transaction);
|
|
92
|
-
transaction.status = enums_1.
|
|
92
|
+
transaction.status = enums_1.AuditTransactionStatus.ROLLED_BACK;
|
|
93
93
|
yield this.transactionRepository.save(transaction);
|
|
94
94
|
});
|
|
95
95
|
}
|
|
@@ -57,11 +57,21 @@ let EntityAuditSubscriber = class EntityAuditSubscriber {
|
|
|
57
57
|
try {
|
|
58
58
|
// 获取上下文信息
|
|
59
59
|
const context = yield this.contextService.getCurrentContext();
|
|
60
|
+
const actionContext = this.contextService.getCurrentActionContext();
|
|
61
|
+
// 记录到审计动作上下文
|
|
62
|
+
if (actionContext) {
|
|
63
|
+
this.contextService.recordEntityChangeInAction(entityType, entityId, enums_1.AuditOperation.CREATE);
|
|
64
|
+
// 记录详细的实体变更数据
|
|
65
|
+
this.contextService.recordDetailedEntityChange(entityType, entityId, enums_1.AuditOperation.CREATE, {}, entity, Object.keys(entity));
|
|
66
|
+
}
|
|
60
67
|
// 记录审计日志
|
|
61
68
|
yield this.entityAuditService.logEntityChange(entityType, entityId, enums_1.AuditOperation.CREATE, {}, entity, {
|
|
62
69
|
requestId: context.requestId,
|
|
63
70
|
requestIp: context.requestIp,
|
|
64
71
|
userAgent: context.userAgent,
|
|
72
|
+
auditActionId: actionContext === null || actionContext === void 0 ? void 0 : actionContext.actionId,
|
|
73
|
+
auditActionName: actionContext === null || actionContext === void 0 ? void 0 : actionContext.actionName,
|
|
74
|
+
sequenceInAction: (actionContext === null || actionContext === void 0 ? void 0 : actionContext.entityChanges.length) || 0,
|
|
65
75
|
});
|
|
66
76
|
}
|
|
67
77
|
catch (error) {
|
|
@@ -91,11 +101,22 @@ let EntityAuditSubscriber = class EntityAuditSubscriber {
|
|
|
91
101
|
try {
|
|
92
102
|
// 获取上下文信息
|
|
93
103
|
const context = yield this.contextService.getCurrentContext();
|
|
104
|
+
const actionContext = this.contextService.getCurrentActionContext();
|
|
105
|
+
// 记录到审计动作上下文
|
|
106
|
+
if (actionContext) {
|
|
107
|
+
this.contextService.recordEntityChangeInAction(entityType, entityId, enums_1.AuditOperation.UPDATE);
|
|
108
|
+
// 记录详细的实体变更数据
|
|
109
|
+
const changedFields = this.calculateChangedFields(databaseEntity || {}, entity);
|
|
110
|
+
this.contextService.recordDetailedEntityChange(entityType, entityId, enums_1.AuditOperation.UPDATE, databaseEntity || {}, entity, changedFields);
|
|
111
|
+
}
|
|
94
112
|
// 记录审计日志
|
|
95
113
|
yield this.entityAuditService.logEntityChange(entityType, entityId, enums_1.AuditOperation.UPDATE, databaseEntity || {}, entity, {
|
|
96
114
|
requestId: context.requestId,
|
|
97
115
|
requestIp: context.requestIp,
|
|
98
116
|
userAgent: context.userAgent,
|
|
117
|
+
auditActionId: actionContext === null || actionContext === void 0 ? void 0 : actionContext.actionId,
|
|
118
|
+
auditActionName: actionContext === null || actionContext === void 0 ? void 0 : actionContext.actionName,
|
|
119
|
+
sequenceInAction: (actionContext === null || actionContext === void 0 ? void 0 : actionContext.entityChanges.length) || 0,
|
|
99
120
|
});
|
|
100
121
|
}
|
|
101
122
|
catch (error) {
|
|
@@ -124,11 +145,21 @@ let EntityAuditSubscriber = class EntityAuditSubscriber {
|
|
|
124
145
|
try {
|
|
125
146
|
// 获取上下文信息
|
|
126
147
|
const context = yield this.contextService.getCurrentContext();
|
|
148
|
+
const actionContext = this.contextService.getCurrentActionContext();
|
|
149
|
+
// 记录到审计动作上下文
|
|
150
|
+
if (actionContext) {
|
|
151
|
+
this.contextService.recordEntityChangeInAction(entityType, entityId, enums_1.AuditOperation.DELETE);
|
|
152
|
+
// 记录详细的实体变更数据
|
|
153
|
+
this.contextService.recordDetailedEntityChange(entityType, entityId, enums_1.AuditOperation.DELETE, entity, {}, Object.keys(entity));
|
|
154
|
+
}
|
|
127
155
|
// 记录审计日志
|
|
128
156
|
yield this.entityAuditService.logEntityChange(entityType, entityId, enums_1.AuditOperation.DELETE, entity, {}, {
|
|
129
157
|
requestId: context.requestId,
|
|
130
158
|
requestIp: context.requestIp,
|
|
131
159
|
userAgent: context.userAgent,
|
|
160
|
+
auditActionId: actionContext === null || actionContext === void 0 ? void 0 : actionContext.actionId,
|
|
161
|
+
auditActionName: actionContext === null || actionContext === void 0 ? void 0 : actionContext.actionName,
|
|
162
|
+
sequenceInAction: (actionContext === null || actionContext === void 0 ? void 0 : actionContext.entityChanges.length) || 0,
|
|
132
163
|
});
|
|
133
164
|
}
|
|
134
165
|
catch (error) {
|
|
@@ -136,6 +167,22 @@ let EntityAuditSubscriber = class EntityAuditSubscriber {
|
|
|
136
167
|
}
|
|
137
168
|
});
|
|
138
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* 计算变更字段
|
|
172
|
+
*/
|
|
173
|
+
calculateChangedFields(oldValue, newValue) {
|
|
174
|
+
const changedFields = [];
|
|
175
|
+
const allKeys = new Set([
|
|
176
|
+
...Object.keys(oldValue || {}),
|
|
177
|
+
...Object.keys(newValue || {}),
|
|
178
|
+
]);
|
|
179
|
+
for (const key of allKeys) {
|
|
180
|
+
if (JSON.stringify(oldValue[key]) !== JSON.stringify(newValue[key])) {
|
|
181
|
+
changedFields.push(key);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return changedFields;
|
|
185
|
+
}
|
|
139
186
|
/**
|
|
140
187
|
* 检查是否启用了审计
|
|
141
188
|
*/
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StreamableFile } from '@nestjs/common';
|
|
2
|
+
import { Response } from 'express';
|
|
3
|
+
import { FileService } from '../services/file.service';
|
|
4
|
+
/**
|
|
5
|
+
* 文件访问控制器
|
|
6
|
+
* 提供文件下载和预览功能
|
|
7
|
+
* 注意:Controller 仅负责 HTTP 层逻辑,业务逻辑在 FileService
|
|
8
|
+
*/
|
|
9
|
+
export declare class FileAccessController {
|
|
10
|
+
private readonly fileService;
|
|
11
|
+
private readonly logger;
|
|
12
|
+
constructor(fileService: FileService);
|
|
13
|
+
/**
|
|
14
|
+
* 通过文件 ID 下载/访问文件
|
|
15
|
+
* GET /files/:id
|
|
16
|
+
*/
|
|
17
|
+
getFile(id: string, res: Response): Promise<StreamableFile>;
|
|
18
|
+
/**
|
|
19
|
+
* 通过文件 ID 下载文件(强制下载)
|
|
20
|
+
* GET /files/:id/download
|
|
21
|
+
*/
|
|
22
|
+
downloadFile(id: string, res: Response): Promise<StreamableFile>;
|
|
23
|
+
}
|