@nest-omni/core 4.1.3-2 → 4.1.3-22
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.d.ts +11 -0
- package/audit/audit.module.js +65 -1
- package/audit/controllers/audit.controller.d.ts +81 -1
- package/audit/controllers/audit.controller.js +67 -0
- package/audit/decorators/audit-action.decorator.d.ts +74 -0
- package/audit/decorators/audit-action.decorator.js +42 -0
- package/audit/decorators/audit-controller.decorator.d.ts +9 -1
- package/audit/decorators/audit-controller.decorator.js +11 -2
- package/audit/decorators/audit-operation.decorator.d.ts +38 -0
- package/audit/decorators/audit-operation.decorator.js +42 -0
- package/audit/decorators/entity-audit.decorator.d.ts +85 -1
- package/audit/decorators/entity-audit.decorator.js +153 -3
- package/audit/decorators/index.d.ts +2 -0
- package/audit/decorators/index.js +2 -0
- package/audit/dto/audit-action-query.dto.d.ts +13 -0
- package/audit/dto/audit-action-query.dto.js +77 -0
- package/audit/dto/audit-log-query.dto.d.ts +3 -0
- package/audit/dto/audit-log-query.dto.js +3 -0
- package/audit/dto/begin-transaction.dto.d.ts +3 -0
- package/audit/dto/begin-transaction.dto.js +3 -0
- package/audit/dto/compare-entities.dto.d.ts +3 -0
- package/audit/dto/compare-entities.dto.js +3 -0
- package/audit/dto/index.d.ts +1 -0
- package/audit/dto/index.js +1 -0
- package/audit/dto/pre-check-restore.dto.d.ts +3 -0
- package/audit/dto/pre-check-restore.dto.js +3 -0
- package/audit/dto/restore-entity.dto.d.ts +3 -0
- package/audit/dto/restore-entity.dto.js +3 -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 +10 -2
- package/audit/entities/entity-audit-log.entity.js +48 -9
- package/audit/entities/entity-transaction.entity.d.ts +11 -2
- package/audit/entities/entity-transaction.entity.js +42 -3
- package/audit/entities/index.d.ts +3 -0
- package/audit/entities/index.js +3 -0
- package/audit/entities/manual-operation-log.entity.d.ts +4 -2
- package/audit/entities/manual-operation-log.entity.js +12 -9
- package/audit/entities/operation-template.entity.d.ts +4 -0
- package/audit/entities/operation-template.entity.js +4 -0
- package/audit/enums/audit.enums.d.ts +29 -6
- package/audit/enums/audit.enums.js +31 -7
- package/audit/examples/decorator-value-mapping.example.d.ts +70 -0
- package/audit/examples/decorator-value-mapping.example.js +414 -0
- package/audit/index.d.ts +5 -1
- package/audit/index.js +38 -1
- package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
- package/audit/interceptors/audit-action.interceptor.js +215 -0
- package/audit/interceptors/audit.interceptor.d.ts +16 -0
- package/audit/interceptors/audit.interceptor.js +41 -11
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +174 -4
- 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 +106 -0
- package/audit/services/audit-context.service.js +185 -0
- package/audit/services/audit-strategy.service.d.ts +6 -0
- package/audit/services/audit-strategy.service.js +13 -0
- package/audit/services/entity-audit.service.d.ts +273 -5
- package/audit/services/entity-audit.service.js +840 -60
- package/audit/services/index.d.ts +3 -0
- package/audit/services/index.js +3 -0
- package/audit/services/manual-audit-log.service.d.ts +133 -9
- package/audit/services/manual-audit-log.service.js +157 -42
- package/audit/services/multi-database.service.d.ts +9 -2
- package/audit/services/multi-database.service.js +9 -21
- package/audit/services/operation-description.service.d.ts +71 -2
- package/audit/services/operation-description.service.js +231 -20
- package/audit/services/transaction-audit.service.d.ts +30 -0
- package/audit/services/transaction-audit.service.js +53 -5
- package/audit/subscribers/entity-audit.subscriber.d.ts +20 -0
- package/audit/subscribers/entity-audit.subscriber.js +98 -6
- package/cache/cache-metrics.service.d.ts +67 -0
- package/cache/cache-metrics.service.js +68 -4
- package/cache/cache-serialization.service.d.ts +31 -0
- package/cache/cache-serialization.service.js +25 -0
- package/cache/cache.constants.d.ts +9 -0
- package/cache/cache.constants.js +9 -0
- package/cache/cache.health.d.ts +26 -0
- package/cache/cache.health.js +30 -0
- package/cache/cache.module.d.ts +87 -2
- package/cache/cache.module.js +84 -11
- package/cache/cache.service.d.ts +143 -3
- package/cache/cache.service.js +173 -4
- package/cache/cache.warmup.service.d.ts +39 -0
- package/cache/cache.warmup.service.js +32 -0
- package/cache/decorators/cache-evict.decorator.d.ts +47 -0
- package/cache/decorators/cache-evict.decorator.js +56 -0
- package/cache/decorators/cache-put.decorator.d.ts +34 -0
- package/cache/decorators/cache-put.decorator.js +39 -0
- package/cache/decorators/cacheable.decorator.d.ts +40 -0
- package/cache/decorators/cacheable.decorator.js +55 -0
- package/cache/dependencies/callback.dependency.d.ts +33 -0
- package/cache/dependencies/callback.dependency.js +39 -1
- package/cache/dependencies/chain.dependency.d.ts +28 -0
- package/cache/dependencies/chain.dependency.js +34 -0
- package/cache/dependencies/db.dependency.d.ts +83 -7
- package/cache/dependencies/db.dependency.js +89 -14
- package/cache/dependencies/file.dependency.d.ts +32 -0
- package/cache/dependencies/file.dependency.js +34 -0
- package/cache/dependencies/tag.dependency.d.ts +75 -4
- package/cache/dependencies/tag.dependency.js +145 -11
- package/cache/dependencies/time.dependency.d.ts +43 -0
- package/cache/dependencies/time.dependency.js +43 -0
- package/cache/entities/index.d.ts +1 -0
- package/cache/entities/index.js +17 -0
- package/cache/entities/typeorm-cache.entity.d.ts +71 -0
- package/cache/entities/typeorm-cache.entity.js +110 -0
- package/cache/examples/basic-usage.d.ts +15 -0
- package/cache/examples/basic-usage.js +62 -8
- package/cache/index.d.ts +2 -1
- package/cache/index.js +28 -2
- package/cache/interfaces/cache-dependency.interface.d.ts +53 -0
- package/cache/interfaces/cache-options.interface.d.ts +89 -0
- package/cache/interfaces/cache-options.interface.js +6 -0
- package/cache/interfaces/cache-provider.interface.d.ts +78 -0
- package/cache/providers/base-cache.provider.d.ts +14 -0
- package/cache/providers/base-cache.provider.js +16 -0
- package/cache/providers/cls-cache.provider.d.ts +20 -0
- package/cache/providers/cls-cache.provider.js +28 -0
- package/cache/providers/index.d.ts +2 -1
- package/cache/providers/index.js +2 -1
- package/cache/providers/lrucache.provider.d.ts +76 -0
- package/cache/providers/lrucache.provider.js +226 -0
- package/cache/providers/redis-cache.provider.d.ts +26 -0
- package/cache/providers/redis-cache.provider.js +29 -0
- package/cache/providers/typeorm-cache.provider.d.ts +211 -0
- package/cache/providers/typeorm-cache.provider.js +483 -0
- package/cache/utils/dependency-manager.util.d.ts +52 -0
- package/cache/utils/dependency-manager.util.js +59 -0
- package/cache/utils/key-generator.util.d.ts +42 -0
- package/cache/utils/key-generator.util.js +53 -1
- package/common/abstract.entity.d.ts +14 -0
- package/common/abstract.entity.js +14 -0
- package/common/boilerplate.polyfill.d.ts +143 -0
- package/common/boilerplate.polyfill.js +35 -1
- package/common/dto/dto-container.d.ts +16 -0
- package/common/dto/dto-container.js +20 -0
- package/common/dto/dto-decorators.d.ts +18 -0
- package/common/dto/dto-decorators.js +14 -0
- package/common/dto/dto-extensions.d.ts +11 -0
- package/common/dto/dto-extensions.js +9 -0
- package/common/dto/dto-service-accessor.d.ts +17 -0
- package/common/dto/dto-service-accessor.js +18 -0
- package/common/dto/dto-transformer.d.ts +12 -0
- package/common/dto/dto-transformer.js +9 -0
- package/common/dto/index.js +2 -0
- package/common/examples/paginate-and-map.example.d.ts +6 -0
- package/common/examples/paginate-and-map.example.js +26 -0
- package/common/helpers/validation-metadata-helper.d.ts +55 -0
- package/common/helpers/validation-metadata-helper.js +60 -0
- package/common/index.d.ts +1 -0
- package/common/index.js +4 -0
- package/common/utils.d.ts +15 -0
- package/common/utils.js +15 -0
- package/constants/language-code.js +1 -0
- package/decorators/field.decorators.d.ts +72 -3
- package/decorators/field.decorators.js +155 -19
- package/decorators/property.decorators.js +1 -0
- package/decorators/public-route.decorator.js +1 -0
- package/decorators/transform.decorators.d.ts +27 -2
- package/decorators/transform.decorators.js +29 -23
- package/decorators/translate.decorator.js +1 -0
- package/decorators/user.decorator.js +1 -0
- package/decorators/validator.decorators.d.ts +8 -18
- package/decorators/validator.decorators.js +22 -190
- 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/column.decorator.d.ts +151 -0
- package/file-upload/decorators/column.decorator.js +273 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +30 -0
- package/file-upload/decorators/csv-data.decorator.js +85 -0
- package/file-upload/decorators/csv-import.decorator.d.ts +34 -0
- package/file-upload/decorators/csv-import.decorator.js +24 -0
- package/file-upload/decorators/examples/column-mapping.example.d.ts +76 -0
- package/file-upload/decorators/examples/column-mapping.example.js +122 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +30 -0
- package/file-upload/decorators/excel-data.decorator.js +85 -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 +5 -0
- package/file-upload/decorators/index.js +38 -0
- package/file-upload/decorators/process.decorator.d.ts +40 -0
- package/file-upload/decorators/process.decorator.js +52 -0
- package/file-upload/decorators/validate-data.decorator.d.ts +91 -0
- package/file-upload/decorators/validate-data.decorator.js +39 -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 +15 -0
- package/file-upload/dto/update-file.dto.js +67 -0
- package/file-upload/entities/file-metadata.entity.d.ts +25 -0
- package/file-upload/entities/file-metadata.entity.js +76 -0
- package/file-upload/entities/file.entity.d.ts +114 -0
- package/file-upload/entities/file.entity.js +350 -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 +292 -0
- package/file-upload/index.d.ts +37 -0
- package/file-upload/index.js +77 -0
- package/file-upload/interceptors/file-upload.interceptor.d.ts +101 -0
- package/file-upload/interceptors/file-upload.interceptor.js +594 -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-processor.interface.d.ts +93 -0
- package/file-upload/interfaces/file-processor.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +74 -0
- package/file-upload/interfaces/file-upload-options.interface.js +5 -0
- package/file-upload/interfaces/index.d.ts +7 -0
- package/file-upload/interfaces/index.js +24 -0
- package/file-upload/interfaces/processor-options.interface.d.ts +102 -0
- package/file-upload/interfaces/processor-options.interface.js +2 -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/processors/csv.processor.d.ts +98 -0
- package/file-upload/processors/csv.processor.js +391 -0
- package/file-upload/processors/excel.processor.d.ts +130 -0
- package/file-upload/processors/excel.processor.js +547 -0
- package/file-upload/processors/image.processor.d.ts +199 -0
- package/file-upload/processors/image.processor.js +377 -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 +193 -0
- package/file-upload/services/file.service.js +638 -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 +300 -0
- package/file-upload/services/malicious-file-detector.service.js +1234 -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 +54 -0
- package/file-upload/utils/dynamic-import.util.js +156 -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/filters/bad-request.filter.js +19 -4
- package/filters/constraint-errors.js +1 -0
- package/helpers/common.helper.d.ts +13 -0
- package/helpers/common.helper.js +13 -0
- package/http-client/config/http-client.config.d.ts +20 -0
- package/http-client/config/http-client.config.js +48 -21
- package/http-client/decorators/http-client.decorators.d.ts +55 -14
- package/http-client/decorators/http-client.decorators.js +154 -78
- package/http-client/entities/http-log.entity.d.ts +217 -8
- package/http-client/entities/http-log.entity.js +7 -22
- package/http-client/errors/http-client.errors.d.ts +57 -0
- package/http-client/errors/http-client.errors.js +58 -0
- package/http-client/examples/advanced-usage.example.d.ts +40 -0
- package/http-client/examples/advanced-usage.example.js +53 -61
- package/http-client/examples/auth-with-waiting-lock.example.d.ts +31 -0
- package/http-client/examples/auth-with-waiting-lock.example.js +52 -5
- package/http-client/examples/basic-usage.example.d.ts +60 -0
- package/http-client/examples/basic-usage.example.js +60 -0
- package/http-client/examples/multi-api-configuration.example.d.ts +60 -0
- package/http-client/examples/multi-api-configuration.example.js +76 -5
- package/http-client/examples/proxy-from-environment.example.d.ts +133 -0
- package/http-client/examples/proxy-from-environment.example.js +409 -0
- package/http-client/http-client.module.d.ts +48 -2
- package/http-client/http-client.module.js +147 -68
- package/http-client/index.d.ts +1 -1
- package/http-client/index.js +8 -0
- package/http-client/interfaces/api-client-config.interface.d.ts +80 -45
- package/http-client/interfaces/api-client-config.interface.js +3 -0
- package/http-client/interfaces/http-client-config.interface.d.ts +109 -52
- package/http-client/services/api-client-registry.service.d.ts +50 -11
- package/http-client/services/api-client-registry.service.js +90 -250
- package/http-client/services/circuit-breaker.service.d.ts +115 -2
- package/http-client/services/circuit-breaker.service.js +237 -7
- package/http-client/services/http-client.service.d.ts +124 -14
- package/http-client/services/http-client.service.js +437 -148
- package/http-client/services/http-log-query.service.d.ts +83 -0
- package/http-client/services/http-log-query.service.js +121 -13
- package/http-client/services/http-replay.service.d.ts +101 -0
- package/http-client/services/http-replay.service.js +86 -0
- package/http-client/services/index.d.ts +0 -1
- package/http-client/services/index.js +0 -1
- package/http-client/services/log-cleanup.service.d.ts +63 -0
- package/http-client/services/log-cleanup.service.js +54 -2
- package/http-client/services/logging.service.d.ts +116 -7
- package/http-client/services/logging.service.js +349 -86
- package/http-client/utils/call-stack-extractor.util.d.ts +63 -0
- package/http-client/utils/call-stack-extractor.util.js +83 -0
- package/http-client/utils/context-extractor.util.d.ts +49 -0
- package/http-client/utils/context-extractor.util.js +54 -0
- package/http-client/utils/curl-generator.util.d.ts +21 -0
- package/http-client/utils/curl-generator.util.js +44 -3
- package/http-client/utils/index.d.ts +1 -0
- package/http-client/utils/index.js +1 -0
- package/http-client/utils/proxy-environment.util.d.ts +42 -0
- package/http-client/utils/proxy-environment.util.js +148 -0
- package/http-client/utils/request-id.util.d.ts +18 -0
- package/http-client/utils/request-id.util.js +20 -0
- package/http-client/utils/retry-recorder.util.d.ts +42 -0
- package/http-client/utils/retry-recorder.util.js +44 -0
- package/http-client/utils/security-validator.util.d.ts +118 -0
- package/http-client/utils/security-validator.util.js +352 -0
- package/index.d.ts +3 -1
- package/index.js +12 -1
- package/interceptors/translation-interceptor.service.js +5 -0
- package/ip-filter/constants.d.ts +21 -0
- package/ip-filter/constants.js +24 -0
- package/ip-filter/decorators/index.d.ts +1 -0
- package/ip-filter/decorators/index.js +17 -0
- package/ip-filter/decorators/ip-filter.decorator.d.ts +58 -0
- package/ip-filter/decorators/ip-filter.decorator.js +79 -0
- package/ip-filter/guards/index.d.ts +1 -0
- package/ip-filter/guards/index.js +17 -0
- package/ip-filter/guards/ip-filter.guard.d.ts +62 -0
- package/ip-filter/guards/ip-filter.guard.js +174 -0
- package/ip-filter/index.d.ts +7 -0
- package/ip-filter/index.js +23 -0
- package/ip-filter/interfaces/index.d.ts +4 -0
- package/ip-filter/interfaces/index.js +20 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.d.ts +15 -0
- package/ip-filter/interfaces/ip-filter-async-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.d.ts +26 -0
- package/ip-filter/interfaces/ip-filter-metadata.interface.js +2 -0
- package/ip-filter/interfaces/ip-filter-options.interface.d.ts +34 -0
- package/ip-filter/interfaces/ip-filter-options.interface.js +2 -0
- package/ip-filter/interfaces/ip-rule.interface.d.ts +36 -0
- package/ip-filter/interfaces/ip-rule.interface.js +2 -0
- package/ip-filter/ip-filter.module.d.ts +55 -0
- package/ip-filter/ip-filter.module.js +105 -0
- package/ip-filter/services/index.d.ts +1 -0
- package/ip-filter/services/index.js +17 -0
- package/ip-filter/services/ip-filter.service.d.ts +92 -0
- package/ip-filter/services/ip-filter.service.js +238 -0
- package/ip-filter/utils/index.d.ts +1 -0
- package/ip-filter/utils/index.js +17 -0
- package/ip-filter/utils/ip-utils.d.ts +61 -0
- package/ip-filter/utils/ip-utils.js +162 -0
- package/package.json +32 -29
- package/providers/context.provider.d.ts +9 -0
- package/providers/context.provider.js +15 -0
- package/providers/generator.provider.d.ts +4 -0
- package/providers/generator.provider.js +4 -0
- package/redis-lock/comprehensive-lock-cleanup.service.d.ts +94 -0
- package/redis-lock/comprehensive-lock-cleanup.service.js +253 -0
- package/redis-lock/examples/lock-strategy.examples.d.ts +89 -0
- package/redis-lock/examples/lock-strategy.examples.js +130 -15
- package/redis-lock/index.d.ts +2 -0
- package/redis-lock/index.js +8 -1
- package/redis-lock/lock-heartbeat.service.d.ts +80 -0
- package/redis-lock/lock-heartbeat.service.js +232 -0
- package/redis-lock/redis-lock.decorator.d.ts +101 -0
- package/redis-lock/redis-lock.decorator.js +120 -0
- package/redis-lock/redis-lock.module.d.ts +66 -0
- package/redis-lock/redis-lock.module.js +175 -70
- package/redis-lock/redis-lock.service.d.ts +282 -0
- package/redis-lock/redis-lock.service.js +343 -20
- package/setup/bootstrap.setup.d.ts +2 -1
- package/setup/bootstrap.setup.js +22 -1
- package/setup/index.d.ts +1 -0
- package/setup/index.js +1 -0
- package/setup/mode.setup.d.ts +44 -0
- package/setup/mode.setup.js +44 -0
- package/setup/run-in-mode.decorator.d.ts +56 -0
- package/setup/run-in-mode.decorator.js +92 -0
- package/setup/schedule.decorator.d.ts +227 -0
- package/setup/schedule.decorator.js +240 -12
- package/setup/worker.decorator.d.ts +86 -0
- package/setup/worker.decorator.js +97 -0
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +19 -18
- package/shared/services/api-config.service.d.ts +3 -0
- package/shared/services/api-config.service.js +21 -9
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- package/validator-json/decorators.d.ts +17 -0
- package/validator-json/decorators.js +17 -2
- package/validator-json/default.d.ts +6 -0
- package/validator-json/default.js +30 -2
- package/validator-json/defaultConverters.js +1 -0
- package/validator-json/options.d.ts +23 -0
- package/validators/common-validators.d.ts +143 -0
- package/validators/common-validators.js +249 -0
- package/validators/custom-validate.examples.d.ts +23 -0
- package/validators/custom-validate.examples.js +78 -6
- package/validators/custom-validate.validator.d.ts +108 -0
- package/validators/custom-validate.validator.js +85 -0
- package/validators/file-mimetype.validator.d.ts +0 -2
- package/validators/file-mimetype.validator.js +4 -6
- package/validators/index.d.ts +1 -0
- package/validators/index.js +1 -0
- package/validators/is-exists.validator.d.ts +26 -6
- package/validators/is-exists.validator.js +30 -7
- package/validators/is-unique.validator.d.ts +33 -7
- package/validators/is-unique.validator.js +59 -17
- package/validators/skip-empty.validator.d.ts +5 -0
- package/validators/skip-empty.validator.js +5 -0
- package/vault/interfaces/vault-options.interface.d.ts +9 -0
- package/vault/vault-config.loader.d.ts +30 -0
- package/vault/vault-config.loader.js +48 -1
- package/vault/vault-config.service.d.ts +53 -0
- package/vault/vault-config.service.js +57 -0
- package/vault/vault.module.d.ts +4 -0
- package/vault/vault.module.js +4 -0
- package/cache/providers/memory-cache.provider.d.ts +0 -26
- package/cache/providers/memory-cache.provider.js +0 -171
- package/decorators/examples/validation-decorators.example.d.ts +0 -69
- package/decorators/examples/validation-decorators.example.js +0 -331
- package/http-client/services/cache.service.d.ts +0 -24
- package/http-client/services/cache.service.js +0 -264
- 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
|
@@ -21,7 +21,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.EntityAuditService = void 0;
|
|
24
|
+
exports.EntityAuditService = exports.AUDIT_CONSTANTS = void 0;
|
|
25
|
+
exports.registerEntityClass = registerEntityClass;
|
|
26
|
+
exports.getEntityClass = getEntityClass;
|
|
25
27
|
const common_1 = require("@nestjs/common");
|
|
26
28
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
27
29
|
const typeorm_2 = require("typeorm");
|
|
@@ -31,34 +33,93 @@ const enums_1 = require("../enums");
|
|
|
31
33
|
const audit_context_service_1 = require("./audit-context.service");
|
|
32
34
|
const audit_strategy_service_1 = require("./audit-strategy.service");
|
|
33
35
|
const multi_database_service_1 = require("./multi-database.service");
|
|
36
|
+
const operation_description_service_1 = require("./operation-description.service");
|
|
34
37
|
const dto_1 = require("../../common/dto");
|
|
38
|
+
const entity_audit_decorator_1 = require("../decorators/entity-audit.decorator");
|
|
39
|
+
const transaction_1 = require("@nest-omni/transaction");
|
|
40
|
+
/**
|
|
41
|
+
* 审计配置常量
|
|
42
|
+
*/
|
|
43
|
+
exports.AUDIT_CONSTANTS = {
|
|
44
|
+
/** 深度比较的最大深度限制 */
|
|
45
|
+
MAX_DIFF_DEPTH: 5,
|
|
46
|
+
/** 深度比较的最大键数量限制 */
|
|
47
|
+
MAX_KEYS: 100,
|
|
48
|
+
/** 描述的最大长度 */
|
|
49
|
+
MAX_DESCRIPTION_LENGTH: 1000,
|
|
50
|
+
/** 哈希截断长度 */
|
|
51
|
+
HASH_TRUNCATE_LENGTH: 64,
|
|
52
|
+
/** 部分掩码显示的字符数 */
|
|
53
|
+
PARTIAL_MASK_CHARS: 2,
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* 实体类注册表 - 用于在运行时通过 entityType 字符串获取实体类引用
|
|
57
|
+
*/
|
|
58
|
+
const ENTITY_CLASS_REGISTRY = new Map();
|
|
59
|
+
/**
|
|
60
|
+
* 注册实体类到注册表
|
|
61
|
+
*/
|
|
62
|
+
function registerEntityClass(entityType, entityClass) {
|
|
63
|
+
ENTITY_CLASS_REGISTRY.set(entityType, entityClass);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 获取实体类
|
|
67
|
+
*/
|
|
68
|
+
function getEntityClass(entityType) {
|
|
69
|
+
return ENTITY_CLASS_REGISTRY.get(entityType);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 实体审计服务
|
|
73
|
+
*/
|
|
35
74
|
let EntityAuditService = class EntityAuditService {
|
|
36
|
-
constructor(auditLogRepository, transactionRepository, entityManager, contextService, multiDbService, auditStrategy = new audit_strategy_service_1.DefaultAuditStrategy(), config, auditConnectionName) {
|
|
75
|
+
constructor(auditLogRepository, transactionRepository, manualOperationRepository, entityManager, contextService, multiDbService, auditStrategy = new audit_strategy_service_1.DefaultAuditStrategy(), config, auditConnectionName, actionSummaryRepository, descriptionService) {
|
|
37
76
|
this.auditLogRepository = auditLogRepository;
|
|
38
77
|
this.transactionRepository = transactionRepository;
|
|
78
|
+
this.manualOperationRepository = manualOperationRepository;
|
|
39
79
|
this.entityManager = entityManager;
|
|
40
80
|
this.contextService = contextService;
|
|
41
81
|
this.multiDbService = multiDbService;
|
|
42
82
|
this.auditStrategy = auditStrategy;
|
|
43
83
|
this.config = config;
|
|
84
|
+
this.actionSummaryRepository = actionSummaryRepository;
|
|
85
|
+
this.descriptionService = descriptionService;
|
|
44
86
|
this.auditConnectionName = auditConnectionName || 'default';
|
|
45
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* 记录实体变更
|
|
90
|
+
*/
|
|
46
91
|
logEntityChange(entityType_1, entityId_1, operation_1, oldValue_1, newValue_1) {
|
|
47
92
|
return __awaiter(this, arguments, void 0, function* (entityType, entityId, operation, oldValue, newValue, metadata = {}) {
|
|
48
|
-
|
|
93
|
+
// 检查是否应该记录
|
|
49
94
|
if (!this.auditStrategy.shouldRecord(entityType, operation)) {
|
|
50
95
|
return null;
|
|
51
96
|
}
|
|
97
|
+
// 获取记录策略
|
|
52
98
|
const recordStrategy = this.auditStrategy.getRecordStrategy(entityType, operation);
|
|
53
99
|
if (recordStrategy === enums_1.RecordStrategy.DISABLED) {
|
|
54
100
|
return null;
|
|
55
101
|
}
|
|
102
|
+
// 获取字段过滤器
|
|
56
103
|
const fieldFilter = this.auditStrategy.getFieldFilter(entityType);
|
|
104
|
+
// 过滤和脱敏字段
|
|
57
105
|
const filteredOldValue = this.filterAndMaskFields(oldValue, fieldFilter);
|
|
58
106
|
const filteredNewValue = this.filterAndMaskFields(newValue, fieldFilter);
|
|
107
|
+
// 计算变更字段
|
|
59
108
|
const changedFields = this.calculateChangedFields(filteredOldValue, filteredNewValue);
|
|
60
|
-
|
|
109
|
+
// 生成字段级别的变更详情(前后对比)
|
|
110
|
+
// CREATE 操作不需要 changeDetails,因为只有新值没有旧值
|
|
111
|
+
const changeDetails = operation === enums_1.AuditOperation.CREATE
|
|
112
|
+
? undefined
|
|
113
|
+
: this.generateChangeDetails(entityType, filteredOldValue, filteredNewValue, changedFields);
|
|
114
|
+
// 获取上下文信息
|
|
61
115
|
const context = yield this.contextService.getCurrentContext();
|
|
116
|
+
// 准备模板键和参数
|
|
117
|
+
const templateKey = metadata.operationTemplateKey || `${entityType}.${operation.toLowerCase()}`;
|
|
118
|
+
const descriptionParams = Object.assign({ entityType,
|
|
119
|
+
entityId, operation: operation.toLowerCase(), changedFields: changedFields.join(', '), changedFieldsCount: changedFields.length }, metadata.descriptionParams);
|
|
120
|
+
// 生成描述(优先使用模板)
|
|
121
|
+
const description = yield this.generateDescriptionFromTemplate(templateKey, descriptionParams, operation, entityType, entityId, changedFields);
|
|
122
|
+
// 创建审计日志
|
|
62
123
|
const auditLog = this.auditLogRepository.create({
|
|
63
124
|
entityType,
|
|
64
125
|
entityId,
|
|
@@ -66,28 +127,37 @@ let EntityAuditService = class EntityAuditService {
|
|
|
66
127
|
oldValue: filteredOldValue,
|
|
67
128
|
newValue: filteredNewValue,
|
|
68
129
|
changedFields,
|
|
69
|
-
|
|
130
|
+
changeDetails,
|
|
70
131
|
userId: context.userId || metadata.userId,
|
|
71
132
|
username: context.username || metadata.username,
|
|
72
133
|
requestId: context.requestId || metadata.requestId,
|
|
73
134
|
requestIp: context.requestIp || metadata.requestIp,
|
|
74
135
|
userAgent: context.userAgent || metadata.userAgent,
|
|
75
|
-
description
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
136
|
+
description,
|
|
137
|
+
operationTemplateKey: templateKey,
|
|
138
|
+
descriptionParams,
|
|
139
|
+
// 新增:审计动作关联字段
|
|
140
|
+
auditActionId: metadata.auditActionId,
|
|
141
|
+
auditActionName: metadata.auditActionName,
|
|
142
|
+
sequenceInAction: metadata.sequenceInAction || 0,
|
|
79
143
|
});
|
|
144
|
+
// 保存变更日志
|
|
80
145
|
const savedLog = yield this.auditLogRepository.save(auditLog);
|
|
81
146
|
return savedLog;
|
|
82
147
|
});
|
|
83
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* 查询审计日志
|
|
151
|
+
*/
|
|
84
152
|
getAuditLogs(query) {
|
|
85
153
|
return __awaiter(this, void 0, void 0, function* () {
|
|
154
|
+
// 应用默认值
|
|
86
155
|
const page = query.page || 1;
|
|
87
156
|
const limit = query.limit || 20;
|
|
88
157
|
const sortBy = query.sortBy || 'createdAt';
|
|
89
158
|
const sortOrder = query.sortOrder || 'DESC';
|
|
90
159
|
const queryBuilder = this.auditLogRepository.createQueryBuilder('log');
|
|
160
|
+
// 应用过滤条件
|
|
91
161
|
if (query.entityType) {
|
|
92
162
|
queryBuilder.andWhere('log.entityType = :entityType', { entityType: query.entityType });
|
|
93
163
|
}
|
|
@@ -111,7 +181,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
111
181
|
search: `%${query.search}%`,
|
|
112
182
|
});
|
|
113
183
|
}
|
|
184
|
+
// 应用排序
|
|
114
185
|
queryBuilder.orderBy(`log.${sortBy}`, sortOrder);
|
|
186
|
+
// 应用分页
|
|
115
187
|
const skip = (page - 1) * limit;
|
|
116
188
|
queryBuilder.skip(skip).take(limit);
|
|
117
189
|
const [data, total] = yield queryBuilder.getManyAndCount();
|
|
@@ -124,6 +196,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
124
196
|
return new dto_1.PageDto(data, pageMetaDto);
|
|
125
197
|
});
|
|
126
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* 比较实体差异
|
|
201
|
+
*/
|
|
127
202
|
compareEntities(entityType, entityId, fromLogId, toLogId) {
|
|
128
203
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
204
|
let fromData = {};
|
|
@@ -137,6 +212,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
137
212
|
toData = (toLog === null || toLog === void 0 ? void 0 : toLog.newValue) || {};
|
|
138
213
|
}
|
|
139
214
|
else {
|
|
215
|
+
// 获取最新的日志
|
|
140
216
|
const latestLog = yield this.auditLogRepository.findOne({
|
|
141
217
|
where: { entityType, entityId },
|
|
142
218
|
order: { createdAt: 'DESC' },
|
|
@@ -146,6 +222,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
146
222
|
return this.compareSnapshotData(fromData, toData);
|
|
147
223
|
});
|
|
148
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* 预检查恢复操作
|
|
227
|
+
*/
|
|
149
228
|
preCheckRestore(entityType, entityId, auditLogId) {
|
|
150
229
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
230
|
const auditLog = yield this.auditLogRepository.findOne({ where: { id: auditLogId } });
|
|
@@ -163,8 +242,11 @@ let EntityAuditService = class EntityAuditService {
|
|
|
163
242
|
warnings: [],
|
|
164
243
|
};
|
|
165
244
|
}
|
|
245
|
+
// 获取当前实体状态
|
|
166
246
|
const repository = this.entityManager.getRepository(entityType);
|
|
167
|
-
const currentEntity = yield repository.findOne({
|
|
247
|
+
const currentEntity = yield repository.findOne({
|
|
248
|
+
where: { id: entityId },
|
|
249
|
+
});
|
|
168
250
|
if (!currentEntity) {
|
|
169
251
|
return {
|
|
170
252
|
canRestore: false,
|
|
@@ -179,6 +261,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
179
261
|
warnings: [],
|
|
180
262
|
};
|
|
181
263
|
}
|
|
264
|
+
// 检查冲突
|
|
182
265
|
const conflicts = this.detectConflicts(currentEntity, auditLog.oldValue);
|
|
183
266
|
return {
|
|
184
267
|
canRestore: conflicts.length === 0,
|
|
@@ -187,6 +270,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
187
270
|
};
|
|
188
271
|
});
|
|
189
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* 恢复实体
|
|
275
|
+
*/
|
|
190
276
|
restoreEntity(entityType_1, entityId_1, auditLogId_1) {
|
|
191
277
|
return __awaiter(this, arguments, void 0, function* (entityType, entityId, auditLogId, options = {}) {
|
|
192
278
|
const auditLog = yield this.auditLogRepository.findOne({ where: { id: auditLogId } });
|
|
@@ -196,6 +282,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
196
282
|
message: '审计日志不存在',
|
|
197
283
|
};
|
|
198
284
|
}
|
|
285
|
+
// 预检查
|
|
199
286
|
const preCheckResult = yield this.preCheckRestore(entityType, entityId, auditLogId);
|
|
200
287
|
if (!preCheckResult.canRestore && !options.force) {
|
|
201
288
|
return {
|
|
@@ -205,10 +292,13 @@ let EntityAuditService = class EntityAuditService {
|
|
|
205
292
|
};
|
|
206
293
|
}
|
|
207
294
|
try {
|
|
295
|
+
// 获取指定的数据库连接
|
|
208
296
|
const connectionName = options.connectionName || 'default';
|
|
209
|
-
const dataSource =
|
|
297
|
+
const dataSource = (0, transaction_1.getDataSource)(connectionName);
|
|
210
298
|
const repository = dataSource.getRepository(entityType);
|
|
299
|
+
// 恢复实体
|
|
211
300
|
const restoreData = Object.assign({}, auditLog.oldValue);
|
|
301
|
+
// 应用字段过滤
|
|
212
302
|
if (options.includeFields && options.includeFields.length > 0) {
|
|
213
303
|
Object.keys(restoreData).forEach((key) => {
|
|
214
304
|
if (!options.includeFields.includes(key)) {
|
|
@@ -221,8 +311,10 @@ let EntityAuditService = class EntityAuditService {
|
|
|
221
311
|
delete restoreData[field];
|
|
222
312
|
});
|
|
223
313
|
}
|
|
314
|
+
// 执行恢复
|
|
224
315
|
if (!options.dryRun) {
|
|
225
316
|
yield repository.update({ id: entityId }, restoreData);
|
|
317
|
+
// 记录恢复操作
|
|
226
318
|
yield this.logEntityChange(entityType, entityId, enums_1.AuditOperation.RESTORE, auditLog.newValue, restoreData);
|
|
227
319
|
}
|
|
228
320
|
return {
|
|
@@ -239,26 +331,96 @@ let EntityAuditService = class EntityAuditService {
|
|
|
239
331
|
}
|
|
240
332
|
});
|
|
241
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* 计算变更字段(支持嵌套路径)
|
|
336
|
+
*/
|
|
242
337
|
calculateChangedFields(oldValue, newValue) {
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const newVal = newValue === null || newValue === void 0 ? void 0 : newValue[field];
|
|
248
|
-
if (!this.deepEqual(oldVal, newVal)) {
|
|
249
|
-
changedFields.push(field);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return changedFields;
|
|
338
|
+
// 使用 deepDiff 获取所有变更,包括嵌套字段
|
|
339
|
+
const diffChanges = this.deepDiff(oldValue, newValue);
|
|
340
|
+
// 将路径数组转换为点号分隔的字符串
|
|
341
|
+
return diffChanges.map(change => change.path.join('.'));
|
|
253
342
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
343
|
+
/**
|
|
344
|
+
* 生成字段级别的变更详情(前后对比,支持嵌套路径和装饰器值映射)
|
|
345
|
+
*/
|
|
346
|
+
generateChangeDetails(entityType, oldValue, newValue, changedFields) {
|
|
347
|
+
const changeDetails = [];
|
|
348
|
+
// 使用 deepDiff 获取详细变更信息
|
|
349
|
+
const diffChanges = this.deepDiff(oldValue, newValue);
|
|
350
|
+
// 尝试获取实体类(用于装饰器值映射)
|
|
351
|
+
const entityClass = getEntityClass(entityType);
|
|
352
|
+
for (const change of diffChanges) {
|
|
353
|
+
const pathStr = change.path.join('.');
|
|
354
|
+
const oldVal = change.oldValue;
|
|
355
|
+
const newVal = change.newValue;
|
|
356
|
+
const fieldName = change.path[0]; // 顶层字段名
|
|
357
|
+
// 确定变更类型
|
|
358
|
+
let changeType;
|
|
359
|
+
if (change.type === 'ADD') {
|
|
360
|
+
changeType = enums_1.ChangeType.ADDED;
|
|
361
|
+
}
|
|
362
|
+
else if (change.type === 'REMOVE') {
|
|
363
|
+
changeType = enums_1.ChangeType.REMOVED;
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
changeType = enums_1.ChangeType.MODIFIED;
|
|
367
|
+
}
|
|
368
|
+
// 尝试从装饰器获取字段标签(支持多语言)
|
|
369
|
+
let fieldLabels;
|
|
370
|
+
let displayOldValue;
|
|
371
|
+
let displayNewValue;
|
|
372
|
+
if (entityClass) {
|
|
373
|
+
try {
|
|
374
|
+
// 获取字段标签(多语言)
|
|
375
|
+
const supportedLanguages = ['zh', 'en', 'ja'];
|
|
376
|
+
fieldLabels = {};
|
|
377
|
+
for (const lang of supportedLanguages) {
|
|
378
|
+
const label = (0, entity_audit_decorator_1.getFieldLabel)(entityClass, pathStr, lang);
|
|
379
|
+
if (label && label !== pathStr) {
|
|
380
|
+
fieldLabels[lang] = label;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// 获取字段值的标签(多语言值映射)
|
|
384
|
+
if (oldVal !== null && oldVal !== undefined) {
|
|
385
|
+
const oldValueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, oldVal, 'zh');
|
|
386
|
+
if (oldValueLabel !== oldVal) {
|
|
387
|
+
// 如果有映射值,创建多语言映射
|
|
388
|
+
displayOldValue = {};
|
|
389
|
+
for (const lang of supportedLanguages) {
|
|
390
|
+
displayOldValue[lang] = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, oldVal, lang);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (newVal !== null && newVal !== undefined) {
|
|
395
|
+
const newValueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, newVal, 'zh');
|
|
396
|
+
if (newValueLabel !== newVal) {
|
|
397
|
+
// 如果有映射值,创建多语言映射
|
|
398
|
+
displayNewValue = {};
|
|
399
|
+
for (const lang of supportedLanguages) {
|
|
400
|
+
displayNewValue[lang] = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, fieldName, newVal, lang);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
// 忽略错误,使用默认值
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
changeDetails.push({
|
|
410
|
+
fieldName: pathStr,
|
|
411
|
+
fieldLabels: Object.keys(fieldLabels || {}).length > 0 ? fieldLabels : undefined,
|
|
412
|
+
oldValue: oldVal,
|
|
413
|
+
newValue: newVal,
|
|
414
|
+
displayOldValue,
|
|
415
|
+
displayNewValue,
|
|
416
|
+
changeType,
|
|
417
|
+
});
|
|
259
418
|
}
|
|
260
|
-
return
|
|
419
|
+
return changeDetails;
|
|
261
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* 深度比较对象
|
|
423
|
+
*/
|
|
262
424
|
deepEqual(a, b) {
|
|
263
425
|
if (a === b)
|
|
264
426
|
return true;
|
|
@@ -282,13 +444,18 @@ let EntityAuditService = class EntityAuditService {
|
|
|
282
444
|
}
|
|
283
445
|
return true;
|
|
284
446
|
}
|
|
285
|
-
|
|
286
|
-
|
|
447
|
+
/**
|
|
448
|
+
* 深度差异比较
|
|
449
|
+
*/
|
|
450
|
+
deepDiff(oldObj, newObj, path = [], visited = new WeakSet()) {
|
|
451
|
+
var _a, _b;
|
|
287
452
|
const changes = [];
|
|
288
|
-
const maxDepth = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.maxDiffDepth)
|
|
453
|
+
const maxDepth = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.maxDiffDepth) !== null && _b !== void 0 ? _b : exports.AUDIT_CONSTANTS.MAX_DIFF_DEPTH;
|
|
454
|
+
// 防止过深
|
|
289
455
|
if (path.length > maxDepth) {
|
|
290
456
|
return changes;
|
|
291
457
|
}
|
|
458
|
+
// 处理基本类型
|
|
292
459
|
if (typeof oldObj !== 'object' || oldObj === null) {
|
|
293
460
|
if (oldObj !== newObj) {
|
|
294
461
|
changes.push({
|
|
@@ -300,6 +467,20 @@ let EntityAuditService = class EntityAuditService {
|
|
|
300
467
|
}
|
|
301
468
|
return changes;
|
|
302
469
|
}
|
|
470
|
+
// 检测循环引用
|
|
471
|
+
if (visited.has(oldObj)) {
|
|
472
|
+
// 检测到循环引用,停止递归
|
|
473
|
+
return changes;
|
|
474
|
+
}
|
|
475
|
+
visited.add(oldObj);
|
|
476
|
+
// 如果newObj也是对象,也加入访问集合
|
|
477
|
+
if (typeof newObj === 'object' && newObj !== null) {
|
|
478
|
+
if (visited.has(newObj)) {
|
|
479
|
+
return changes;
|
|
480
|
+
}
|
|
481
|
+
visited.add(newObj);
|
|
482
|
+
}
|
|
483
|
+
// 处理数组
|
|
303
484
|
if (Array.isArray(oldObj)) {
|
|
304
485
|
if (!Array.isArray(newObj)) {
|
|
305
486
|
changes.push({
|
|
@@ -320,11 +501,22 @@ let EntityAuditService = class EntityAuditService {
|
|
|
320
501
|
return changes;
|
|
321
502
|
}
|
|
322
503
|
for (let i = 0; i < oldObj.length; i++) {
|
|
323
|
-
changes.push(...this.deepDiff(oldObj[i], newObj[i], [...path, i.toString()]));
|
|
504
|
+
changes.push(...this.deepDiff(oldObj[i], newObj[i], [...path, i.toString()], visited));
|
|
324
505
|
}
|
|
325
506
|
return changes;
|
|
326
507
|
}
|
|
508
|
+
// 处理对象
|
|
327
509
|
const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);
|
|
510
|
+
// 添加键数量限制,防止内存溢出
|
|
511
|
+
if (allKeys.size > exports.AUDIT_CONSTANTS.MAX_KEYS) {
|
|
512
|
+
changes.push({
|
|
513
|
+
path,
|
|
514
|
+
type: 'CHANGE',
|
|
515
|
+
oldValue: `[Object with too many keys: ${allKeys.size}]`,
|
|
516
|
+
newValue: `[Object with too many keys: ${allKeys.size}]`,
|
|
517
|
+
});
|
|
518
|
+
return changes;
|
|
519
|
+
}
|
|
328
520
|
for (const key of allKeys) {
|
|
329
521
|
const oldVal = oldObj[key];
|
|
330
522
|
const newVal = newObj[key];
|
|
@@ -345,11 +537,14 @@ let EntityAuditService = class EntityAuditService {
|
|
|
345
537
|
});
|
|
346
538
|
}
|
|
347
539
|
else {
|
|
348
|
-
changes.push(...this.deepDiff(oldVal, newVal, [...path, key]));
|
|
540
|
+
changes.push(...this.deepDiff(oldVal, newVal, [...path, key], visited));
|
|
349
541
|
}
|
|
350
542
|
}
|
|
351
543
|
return changes;
|
|
352
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* 比较快照数据
|
|
547
|
+
*/
|
|
353
548
|
compareSnapshotData(fromData, toData) {
|
|
354
549
|
const changes = this.deepDiff(fromData, toData);
|
|
355
550
|
return {
|
|
@@ -361,6 +556,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
361
556
|
},
|
|
362
557
|
};
|
|
363
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* 过滤和脱敏字段
|
|
561
|
+
*/
|
|
364
562
|
filterAndMaskFields(data, fieldFilter, path = []) {
|
|
365
563
|
if (typeof data !== 'object' || data === null) {
|
|
366
564
|
return data;
|
|
@@ -368,14 +566,17 @@ let EntityAuditService = class EntityAuditService {
|
|
|
368
566
|
const result = {};
|
|
369
567
|
for (const [key, value] of Object.entries(data)) {
|
|
370
568
|
const currentPath = [...path, key];
|
|
569
|
+
// 检查是否应该包含此字段
|
|
371
570
|
if (!fieldFilter.shouldIncludeField(key, currentPath)) {
|
|
372
571
|
continue;
|
|
373
572
|
}
|
|
573
|
+
// 检查是否应该脱敏此字段
|
|
374
574
|
if (fieldFilter.shouldMaskField(key, currentPath)) {
|
|
375
575
|
const maskingStrategy = fieldFilter.getMaskingStrategy(key, currentPath);
|
|
376
576
|
result[key] = this.applyMasking(value, maskingStrategy);
|
|
377
577
|
}
|
|
378
578
|
else if (typeof value === 'object' && value !== null) {
|
|
579
|
+
// 递归处理嵌套对象
|
|
379
580
|
result[key] = this.filterAndMaskFields(value, fieldFilter, currentPath);
|
|
380
581
|
}
|
|
381
582
|
else {
|
|
@@ -384,6 +585,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
384
585
|
}
|
|
385
586
|
return result;
|
|
386
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* 应用脱敏策略
|
|
590
|
+
*/
|
|
387
591
|
applyMasking(value, strategy) {
|
|
388
592
|
if (value == null)
|
|
389
593
|
return value;
|
|
@@ -400,42 +604,65 @@ let EntityAuditService = class EntityAuditService {
|
|
|
400
604
|
return '***MASKED***';
|
|
401
605
|
}
|
|
402
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* 哈希值
|
|
609
|
+
*/
|
|
403
610
|
hashValue(value) {
|
|
404
611
|
const strValue = String(value);
|
|
405
612
|
return (0, crypto_1.createHash)('sha256').update(strValue).digest('hex');
|
|
406
613
|
}
|
|
614
|
+
/**
|
|
615
|
+
* 掩码值
|
|
616
|
+
*/
|
|
407
617
|
maskValue(value) {
|
|
408
618
|
const strValue = String(value);
|
|
409
619
|
return '*'.repeat(strValue.length);
|
|
410
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* 部分掩码值
|
|
623
|
+
*/
|
|
411
624
|
partialMaskValue(value) {
|
|
412
625
|
const strValue = String(value);
|
|
413
|
-
|
|
626
|
+
const maskChars = exports.AUDIT_CONSTANTS.PARTIAL_MASK_CHARS;
|
|
627
|
+
if (strValue.length <= maskChars * 2) {
|
|
414
628
|
return '*'.repeat(strValue.length);
|
|
415
629
|
}
|
|
416
|
-
return (strValue.substring(0,
|
|
417
|
-
'*'.repeat(strValue.length -
|
|
418
|
-
strValue.substring(strValue.length -
|
|
630
|
+
return (strValue.substring(0, maskChars) +
|
|
631
|
+
'*'.repeat(strValue.length - maskChars * 2) +
|
|
632
|
+
strValue.substring(strValue.length - maskChars));
|
|
419
633
|
}
|
|
420
|
-
|
|
634
|
+
/**
|
|
635
|
+
* 生成描述(支持多语言)
|
|
636
|
+
* @param operation 操作类型
|
|
637
|
+
* @param entityType 实体类型
|
|
638
|
+
* @param entityId 实体ID
|
|
639
|
+
* @param changedFields 变更字段列表
|
|
640
|
+
* @param language 语言(默认中文)
|
|
641
|
+
* @param entityClass 实体类(可选,用于获取实体标签)
|
|
642
|
+
*/
|
|
643
|
+
/**
|
|
644
|
+
* 使用模板生成描述(优先使用 OperationDescriptionService)
|
|
645
|
+
*/
|
|
646
|
+
generateDescriptionFromTemplate(templateKey, descriptionParams, operation, entityType, entityId, changedFields) {
|
|
421
647
|
return __awaiter(this, void 0, void 0, function* () {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
648
|
+
// 优先尝试使用 OperationDescriptionService
|
|
649
|
+
if (this.descriptionService) {
|
|
650
|
+
try {
|
|
651
|
+
const templateDescription = yield this.descriptionService.generateDescription(templateKey, descriptionParams, 'zh');
|
|
652
|
+
// 如果成功获取到模板描述且不是原始的 templateKey,则使用它
|
|
653
|
+
if (templateDescription && templateDescription !== templateKey) {
|
|
654
|
+
return templateDescription;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
catch (error) {
|
|
658
|
+
// 模板服务失败,降级到原有方式
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
// 降级:使用原有的描述生成逻辑
|
|
662
|
+
return this.generateDescription(operation, entityType, entityId, changedFields);
|
|
436
663
|
});
|
|
437
664
|
}
|
|
438
|
-
generateDescription(operation, entityType, entityId, changedFields) {
|
|
665
|
+
generateDescription(operation, entityType, entityId, changedFields, language = 'zh', entityClass) {
|
|
439
666
|
const operationText = {
|
|
440
667
|
[enums_1.AuditOperation.CREATE]: '创建',
|
|
441
668
|
[enums_1.AuditOperation.UPDATE]: '更新',
|
|
@@ -443,11 +670,36 @@ let EntityAuditService = class EntityAuditService {
|
|
|
443
670
|
[enums_1.AuditOperation.RESTORE]: '恢复',
|
|
444
671
|
};
|
|
445
672
|
const text = operationText[operation] || operation;
|
|
673
|
+
// 尝试获取实体的多语言标签
|
|
674
|
+
let entityLabel = entityType;
|
|
675
|
+
if (entityClass) {
|
|
676
|
+
try {
|
|
677
|
+
entityLabel = (0, entity_audit_decorator_1.getEntityLabel)(entityClass, language);
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
// 忽略错误,使用默认的 entityType
|
|
681
|
+
}
|
|
682
|
+
}
|
|
446
683
|
if (operation === enums_1.AuditOperation.UPDATE && changedFields.length > 0) {
|
|
447
|
-
|
|
684
|
+
// 对于更新操作,显示哪些字段发生了变化
|
|
685
|
+
const fieldLabels = changedFields.map(field => {
|
|
686
|
+
if (entityClass) {
|
|
687
|
+
try {
|
|
688
|
+
return (0, entity_audit_decorator_1.getFieldLabel)(entityClass, field, language);
|
|
689
|
+
}
|
|
690
|
+
catch (error) {
|
|
691
|
+
return field;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return field;
|
|
695
|
+
});
|
|
696
|
+
return `${text}${entityLabel}(${entityId}), 变更字段: ${fieldLabels.join('、')}`;
|
|
448
697
|
}
|
|
449
|
-
return `${text}
|
|
698
|
+
return `${text}${entityLabel}(${entityId})`;
|
|
450
699
|
}
|
|
700
|
+
/**
|
|
701
|
+
* 检测冲突
|
|
702
|
+
*/
|
|
451
703
|
detectConflicts(currentEntity, targetValue) {
|
|
452
704
|
const conflicts = [];
|
|
453
705
|
for (const [key, targetVal] of Object.entries(targetValue)) {
|
|
@@ -463,22 +715,550 @@ let EntityAuditService = class EntityAuditService {
|
|
|
463
715
|
}
|
|
464
716
|
return conflicts;
|
|
465
717
|
}
|
|
718
|
+
// ========== 新增方法:支持模板和手动操作 ==========
|
|
719
|
+
/**
|
|
720
|
+
* 增强的记录实体变更(支持模板和结构化变更详情)
|
|
721
|
+
* @param data 审计数据
|
|
722
|
+
* @returns 审计日志实体
|
|
723
|
+
*/
|
|
724
|
+
logEntityChangeWithTemplate(data) {
|
|
725
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
726
|
+
var _a, _b, _c, _d, _e;
|
|
727
|
+
// 检查是否应该记录
|
|
728
|
+
if (!this.auditStrategy.shouldRecord(data.entityType, data.operation)) {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
// 获取记录策略
|
|
732
|
+
const recordStrategy = this.auditStrategy.getRecordStrategy(data.entityType, data.operation);
|
|
733
|
+
if (recordStrategy === enums_1.RecordStrategy.DISABLED) {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
// 获取字段过滤器
|
|
737
|
+
const fieldFilter = this.auditStrategy.getFieldFilter(data.entityType);
|
|
738
|
+
// 过滤和脱敏字段
|
|
739
|
+
const filteredOldValue = this.filterAndMaskFields(data.oldValue || {}, fieldFilter);
|
|
740
|
+
const filteredNewValue = this.filterAndMaskFields(data.newValue || {}, fieldFilter);
|
|
741
|
+
// 计算变更字段
|
|
742
|
+
const changedFields = data.changedFields || this.calculateChangedFields(filteredOldValue, filteredNewValue);
|
|
743
|
+
// 获取上下文信息
|
|
744
|
+
const context = yield this.contextService.getCurrentContext();
|
|
745
|
+
// 如果没有提供操作模板键,使用默认模板
|
|
746
|
+
const operationTemplateKey = data.operationTemplateKey || `${data.entityType}.${data.operation}`;
|
|
747
|
+
// 如果没有提供描述参数,使用实体数据
|
|
748
|
+
const descriptionParams = data.descriptionParams || Object.assign(Object.assign(Object.assign({}, filteredOldValue), filteredNewValue), { changedFields, changedFieldsCount: changedFields.length });
|
|
749
|
+
// 创建审计日志
|
|
750
|
+
const auditLog = this.auditLogRepository.create({
|
|
751
|
+
entityType: data.entityType,
|
|
752
|
+
entityId: data.entityId,
|
|
753
|
+
operation: data.operation,
|
|
754
|
+
oldValue: filteredOldValue,
|
|
755
|
+
newValue: filteredNewValue,
|
|
756
|
+
changedFields,
|
|
757
|
+
userId: context.userId || ((_a = data.metadata) === null || _a === void 0 ? void 0 : _a.userId),
|
|
758
|
+
username: context.username || ((_b = data.metadata) === null || _b === void 0 ? void 0 : _b.username),
|
|
759
|
+
requestId: context.requestId || ((_c = data.metadata) === null || _c === void 0 ? void 0 : _c.requestId),
|
|
760
|
+
requestIp: context.requestIp || ((_d = data.metadata) === null || _d === void 0 ? void 0 : _d.requestIp),
|
|
761
|
+
userAgent: context.userAgent || ((_e = data.metadata) === null || _e === void 0 ? void 0 : _e.userAgent),
|
|
762
|
+
description: this.generateDescription(data.operation, data.entityType, data.entityId, changedFields),
|
|
763
|
+
// 新增字段
|
|
764
|
+
operationTemplateKey,
|
|
765
|
+
descriptionParams,
|
|
766
|
+
changeDetails: data.changeDetails,
|
|
767
|
+
});
|
|
768
|
+
// 保存变更日志
|
|
769
|
+
const savedLog = yield this.auditLogRepository.save(auditLog);
|
|
770
|
+
return savedLog;
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* 记录手动操作
|
|
775
|
+
* @param data 手动操作数据
|
|
776
|
+
* @returns 手动操作日志实体
|
|
777
|
+
*/
|
|
778
|
+
logManualOperation(data) {
|
|
779
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
780
|
+
// 获取上下文信息
|
|
781
|
+
const context = yield this.contextService.getCurrentContext();
|
|
782
|
+
const manualLog = this.manualOperationRepository.create({
|
|
783
|
+
transactionId: data.transactionId,
|
|
784
|
+
operationTemplateKey: data.operationTemplateKey,
|
|
785
|
+
descriptionParams: data.descriptionParams,
|
|
786
|
+
userId: data.userId || context.userId,
|
|
787
|
+
username: data.username || context.username,
|
|
788
|
+
requestIp: data.requestIp || context.requestIp,
|
|
789
|
+
});
|
|
790
|
+
return yield this.manualOperationRepository.save(manualLog);
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* 在事务中执行操作
|
|
795
|
+
* @param fn 执行函数
|
|
796
|
+
* @param options 事务选项
|
|
797
|
+
* @returns 执���结果
|
|
798
|
+
*/
|
|
799
|
+
withTransaction(fn, options) {
|
|
800
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
801
|
+
var _a;
|
|
802
|
+
// 获取上下文信息
|
|
803
|
+
const context = yield this.contextService.getCurrentContext();
|
|
804
|
+
// 创建事务
|
|
805
|
+
const transaction = this.transactionRepository.create({
|
|
806
|
+
description: ((_a = options === null || options === void 0 ? void 0 : options.descriptionParams) === null || _a === void 0 ? void 0 : _a.description) || 'Transaction',
|
|
807
|
+
status: 'PENDING',
|
|
808
|
+
entities: [],
|
|
809
|
+
userId: (options === null || options === void 0 ? void 0 : options.userId) || context.userId,
|
|
810
|
+
username: (options === null || options === void 0 ? void 0 : options.username) || context.username,
|
|
811
|
+
requestIp: (options === null || options === void 0 ? void 0 : options.requestIp) || context.requestIp,
|
|
812
|
+
operationTemplateKey: options === null || options === void 0 ? void 0 : options.operationTemplateKey,
|
|
813
|
+
descriptionParams: options === null || options === void 0 ? void 0 : options.descriptionParams,
|
|
814
|
+
metadata: options === null || options === void 0 ? void 0 : options.metadata,
|
|
815
|
+
});
|
|
816
|
+
const savedTransaction = yield this.transactionRepository.save(transaction);
|
|
817
|
+
const transactionId = savedTransaction.id;
|
|
818
|
+
try {
|
|
819
|
+
// 设置事务ID到上下文
|
|
820
|
+
yield this.contextService.setContext(Object.assign(Object.assign({}, context), { transactionId }));
|
|
821
|
+
// 执行操作
|
|
822
|
+
const result = yield fn(transactionId);
|
|
823
|
+
// 提交事务
|
|
824
|
+
yield this.transactionRepository.update(transactionId, {
|
|
825
|
+
status: 'COMMITTED',
|
|
826
|
+
completedAt: new Date(),
|
|
827
|
+
});
|
|
828
|
+
return result;
|
|
829
|
+
}
|
|
830
|
+
catch (error) {
|
|
831
|
+
// 回滚事务
|
|
832
|
+
yield this.transactionRepository.update(transactionId, {
|
|
833
|
+
status: 'ROLLED_BACK',
|
|
834
|
+
completedAt: new Date(),
|
|
835
|
+
});
|
|
836
|
+
throw error;
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* 获取当前事务ID
|
|
842
|
+
* @returns 当前事务ID或null
|
|
843
|
+
*/
|
|
844
|
+
getCurrentTransactionId() {
|
|
845
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
846
|
+
const context = yield this.contextService.getCurrentContext();
|
|
847
|
+
return context.transactionId || null;
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* 设置当前事务ID
|
|
852
|
+
* @param transactionId 事务ID
|
|
853
|
+
*/
|
|
854
|
+
setCurrentTransactionId(transactionId) {
|
|
855
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
856
|
+
const context = yield this.contextService.getCurrentContext();
|
|
857
|
+
yield this.contextService.setContext(Object.assign(Object.assign({}, context), { transactionId }));
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* 开始事务
|
|
862
|
+
* @param userId 用户ID
|
|
863
|
+
* @param userName 用户名
|
|
864
|
+
* @param ip IP地址
|
|
865
|
+
* @param operationTemplateKey 操作模板键
|
|
866
|
+
* @param descriptionParams 描述参数
|
|
867
|
+
* @returns 事务ID
|
|
868
|
+
*/
|
|
869
|
+
beginTransaction(userId, userName, ip, operationTemplateKey, descriptionParams) {
|
|
870
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
871
|
+
// 获取上下文信息
|
|
872
|
+
const context = yield this.contextService.getCurrentContext();
|
|
873
|
+
// 创建事务
|
|
874
|
+
const transaction = this.transactionRepository.create({
|
|
875
|
+
description: (descriptionParams === null || descriptionParams === void 0 ? void 0 : descriptionParams.description) || 'Transaction',
|
|
876
|
+
status: 'pending',
|
|
877
|
+
entities: [],
|
|
878
|
+
userId: userId || context.userId,
|
|
879
|
+
username: userName || context.username,
|
|
880
|
+
requestIp: ip || context.requestIp,
|
|
881
|
+
operationTemplateKey,
|
|
882
|
+
descriptionParams,
|
|
883
|
+
});
|
|
884
|
+
const savedTransaction = yield this.transactionRepository.save(transaction);
|
|
885
|
+
return savedTransaction.id;
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* 提交事务
|
|
890
|
+
* @param transactionId 事务ID
|
|
891
|
+
*/
|
|
892
|
+
commitTransaction(transactionId) {
|
|
893
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
894
|
+
yield this.transactionRepository.update(transactionId, {
|
|
895
|
+
status: 'committed',
|
|
896
|
+
completedAt: new Date(),
|
|
897
|
+
});
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* 回滚事务
|
|
902
|
+
* @param transactionId 事务ID
|
|
903
|
+
*/
|
|
904
|
+
rollbackTransaction(transactionId) {
|
|
905
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
906
|
+
yield this.transactionRepository.update(transactionId, {
|
|
907
|
+
status: 'rolled_back',
|
|
908
|
+
completedAt: new Date(),
|
|
909
|
+
});
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* 查询审计动作汇总记录
|
|
914
|
+
*/
|
|
915
|
+
getAuditActions(options) {
|
|
916
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
917
|
+
if (!this.actionSummaryRepository) {
|
|
918
|
+
throw new Error('AuditActionSummaryEntity repository not available');
|
|
919
|
+
}
|
|
920
|
+
const { page = 1, limit = 20 } = options;
|
|
921
|
+
const queryBuilder = this.actionSummaryRepository.createQueryBuilder('action');
|
|
922
|
+
// 应用过滤条件
|
|
923
|
+
if (options.userId) {
|
|
924
|
+
queryBuilder.andWhere('action.userId = :userId', { userId: options.userId });
|
|
925
|
+
}
|
|
926
|
+
if (options.username) {
|
|
927
|
+
queryBuilder.andWhere('action.username LIKE :username', { username: `%${options.username}%` });
|
|
928
|
+
}
|
|
929
|
+
if (options.actionName) {
|
|
930
|
+
// 支持模糊匹配动作名
|
|
931
|
+
queryBuilder.andWhere('action.actionName LIKE :actionName', { actionName: `%${options.actionName}%` });
|
|
932
|
+
}
|
|
933
|
+
// 新增:全局关键词搜索(搜索多个字段)
|
|
934
|
+
if (options.keyword) {
|
|
935
|
+
queryBuilder.andWhere('(action.username LIKE :keyword OR action.actionName LIKE :keyword OR action.description LIKE :keyword)', { keyword: `%${options.keyword}%` });
|
|
936
|
+
}
|
|
937
|
+
if (options.success !== undefined) {
|
|
938
|
+
queryBuilder.andWhere('action.success = :success', { success: options.success });
|
|
939
|
+
}
|
|
940
|
+
if (options.startTime && options.endTime) {
|
|
941
|
+
queryBuilder.andWhere('action.createdAt BETWEEN :startTime AND :endTime', {
|
|
942
|
+
startTime: options.startTime,
|
|
943
|
+
endTime: options.endTime,
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
// 排序
|
|
947
|
+
queryBuilder.orderBy('action.createdAt', 'DESC');
|
|
948
|
+
// 分页
|
|
949
|
+
const skip = (page - 1) * limit;
|
|
950
|
+
queryBuilder.skip(skip).take(limit);
|
|
951
|
+
const [data, total] = yield queryBuilder.getManyAndCount();
|
|
952
|
+
const pageOptionsDto = new dto_1.PageOptionsDto();
|
|
953
|
+
Object.assign(pageOptionsDto, { page, pageSize: limit });
|
|
954
|
+
const pageMetaDto = new dto_1.PageMetaDto({
|
|
955
|
+
pageOptionsDto,
|
|
956
|
+
itemCount: total,
|
|
957
|
+
});
|
|
958
|
+
return new dto_1.PageDto(data, pageMetaDto);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* 查询单个审计动作的详细信息(包含关联的实体变更)
|
|
963
|
+
* @param actionId 动作ID
|
|
964
|
+
* @param language 语言代码 (zh/en/ja),默认 zh
|
|
965
|
+
*/
|
|
966
|
+
getAuditActionDetail(actionId_1) {
|
|
967
|
+
return __awaiter(this, arguments, void 0, function* (actionId, language = 'zh') {
|
|
968
|
+
if (!this.actionSummaryRepository) {
|
|
969
|
+
throw new Error('AuditActionSummaryEntity repository not available');
|
|
970
|
+
}
|
|
971
|
+
// 查询汇总信息
|
|
972
|
+
const summary = yield this.actionSummaryRepository.findOne({
|
|
973
|
+
where: { id: actionId },
|
|
974
|
+
});
|
|
975
|
+
if (!summary) {
|
|
976
|
+
throw new Error(`Audit action with id ${actionId} not found`);
|
|
977
|
+
}
|
|
978
|
+
// 动态生成多语言描述
|
|
979
|
+
const description = yield this.generateLocalizedDescription(summary.operationTemplateKey, summary.actionName, summary.descriptionParams, summary.success, language);
|
|
980
|
+
// 查询关联的实体变更
|
|
981
|
+
const entityChanges = yield this.auditLogRepository.find({
|
|
982
|
+
where: { auditActionId: actionId },
|
|
983
|
+
order: { sequenceInAction: 'ASC' },
|
|
984
|
+
});
|
|
985
|
+
// 分析每个实体的详细变化(支持多语言)
|
|
986
|
+
const detailedChanges = entityChanges.map((change) => {
|
|
987
|
+
// 使用数据库中存储的 changeDetails,并根据语言转换
|
|
988
|
+
const changeDetails = this.localizeChangeDetails(change.changeDetails, language);
|
|
989
|
+
return {
|
|
990
|
+
id: change.id,
|
|
991
|
+
entityType: change.entityType,
|
|
992
|
+
entityId: change.entityId,
|
|
993
|
+
operation: change.operation,
|
|
994
|
+
operationLabel: this.getOperationLabel(change.operation, language),
|
|
995
|
+
description: change.description,
|
|
996
|
+
sequenceInAction: change.sequenceInAction,
|
|
997
|
+
createdAt: change.createdAt,
|
|
998
|
+
// 数据快照
|
|
999
|
+
oldValue: change.oldValue,
|
|
1000
|
+
newValue: change.newValue,
|
|
1001
|
+
// 详细的字段变化分析 (使用本地化的 changeDetails)
|
|
1002
|
+
changeDetails,
|
|
1003
|
+
changedFieldsCount: (changeDetails === null || changeDetails === void 0 ? void 0 : changeDetails.length) || 0,
|
|
1004
|
+
changedFields: change.changedFields,
|
|
1005
|
+
};
|
|
1006
|
+
});
|
|
1007
|
+
// 统计信息
|
|
1008
|
+
const statistics = {
|
|
1009
|
+
totalChanges: entityChanges.length,
|
|
1010
|
+
totalFieldChanges: detailedChanges.reduce((sum, c) => sum + c.changedFieldsCount, 0),
|
|
1011
|
+
byEntityType: this.groupBy(entityChanges, 'entityType'),
|
|
1012
|
+
byOperation: this.groupBy(entityChanges, 'operation'),
|
|
1013
|
+
operationSequence: entityChanges.map((c) => ({
|
|
1014
|
+
sequence: c.sequenceInAction,
|
|
1015
|
+
entityType: c.entityType,
|
|
1016
|
+
operation: c.operation,
|
|
1017
|
+
})),
|
|
1018
|
+
};
|
|
1019
|
+
return {
|
|
1020
|
+
// 汇总信息(使用本地化描述)
|
|
1021
|
+
summary: {
|
|
1022
|
+
id: summary.id,
|
|
1023
|
+
actionName: summary.actionName,
|
|
1024
|
+
operationTemplateKey: summary.operationTemplateKey,
|
|
1025
|
+
description,
|
|
1026
|
+
descriptionParams: summary.descriptionParams,
|
|
1027
|
+
success: summary.success,
|
|
1028
|
+
errorMessage: summary.errorMessage,
|
|
1029
|
+
duration: summary.duration,
|
|
1030
|
+
userId: summary.userId,
|
|
1031
|
+
username: summary.username,
|
|
1032
|
+
requestId: summary.requestId,
|
|
1033
|
+
requestIp: summary.requestIp,
|
|
1034
|
+
userAgent: summary.userAgent,
|
|
1035
|
+
entityChangesCount: summary.entityChangesCount,
|
|
1036
|
+
entityTypes: summary.entityTypes,
|
|
1037
|
+
operationStats: summary.operationStats,
|
|
1038
|
+
createdAt: summary.createdAt,
|
|
1039
|
+
metadata: summary.metadata,
|
|
1040
|
+
},
|
|
1041
|
+
// 原始实体变更记录
|
|
1042
|
+
entityChanges,
|
|
1043
|
+
// 详细的变化分析
|
|
1044
|
+
detailedChanges,
|
|
1045
|
+
// 统计信息
|
|
1046
|
+
statistics,
|
|
1047
|
+
};
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* 生成本地化的描述文本
|
|
1052
|
+
*/
|
|
1053
|
+
generateLocalizedDescription(templateKey, actionName, params, success, language) {
|
|
1054
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1055
|
+
var _a;
|
|
1056
|
+
let template;
|
|
1057
|
+
// 1. 尝试从模板服务获取多语言模板
|
|
1058
|
+
if (templateKey && this.descriptionService) {
|
|
1059
|
+
try {
|
|
1060
|
+
template = yield this.descriptionService.getTemplate(templateKey, language);
|
|
1061
|
+
}
|
|
1062
|
+
catch (error) {
|
|
1063
|
+
// 如果获取模板失败,继续使用默认逻辑
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
// 2. 如果没有模板,使用默认格式
|
|
1067
|
+
if (!template) {
|
|
1068
|
+
const actionLabels = {
|
|
1069
|
+
zh: { success: '执行操作', fail: '执行操作失败' },
|
|
1070
|
+
en: { success: 'Executed operation', fail: 'Operation failed' },
|
|
1071
|
+
ja: { success: '操作を実行', fail: '操作が失敗しました' },
|
|
1072
|
+
};
|
|
1073
|
+
const label = ((_a = actionLabels[language]) === null || _a === void 0 ? void 0 : _a[success ? 'success' : 'fail']) || actionLabels.zh[success ? 'success' : 'fail'];
|
|
1074
|
+
template = `${label}: ${actionName}`;
|
|
1075
|
+
}
|
|
1076
|
+
// 3. 执行模板替换
|
|
1077
|
+
return this.replaceTemplatePlaceholders(template, params);
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* 替换模板中的占位符
|
|
1082
|
+
* @param template 模板字符串,如 "创建了产品 {name},价格 ¥{price}"
|
|
1083
|
+
* @param params 参数对象,如 { name: "iPhone", price: 999 }
|
|
1084
|
+
* @returns 替换后的字符串
|
|
1085
|
+
*/
|
|
1086
|
+
replaceTemplatePlaceholders(template, params) {
|
|
1087
|
+
let result = template;
|
|
1088
|
+
// 匹配 {paramName} 格式的占位符
|
|
1089
|
+
const placeholderPattern = /\{([^}]+)\}/g;
|
|
1090
|
+
result = result.replace(placeholderPattern, (match, paramName) => {
|
|
1091
|
+
// 支持嵌套属性访问,如 {user.name}
|
|
1092
|
+
const value = this.getNestedValue(params, paramName);
|
|
1093
|
+
return value !== undefined && value !== null ? String(value) : match;
|
|
1094
|
+
});
|
|
1095
|
+
return result;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* 获取嵌套对象的值
|
|
1099
|
+
* @param obj 对象
|
|
1100
|
+
* @param path 路径,如 "user.name" 或 "user.profile.age"
|
|
1101
|
+
* @returns 值或 undefined
|
|
1102
|
+
*/
|
|
1103
|
+
getNestedValue(obj, path) {
|
|
1104
|
+
return path.split('.').reduce((current, key) => {
|
|
1105
|
+
return current === null || current === void 0 ? void 0 : current[key];
|
|
1106
|
+
}, obj);
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* 本地化 changeDetails(根据语言转换 fieldLabel 和 displayValue)
|
|
1110
|
+
*/
|
|
1111
|
+
localizeChangeDetails(changeDetails, language) {
|
|
1112
|
+
if (!changeDetails)
|
|
1113
|
+
return undefined;
|
|
1114
|
+
return changeDetails.map((detail) => {
|
|
1115
|
+
var _a, _b, _c, _d, _e;
|
|
1116
|
+
return (Object.assign(Object.assign({}, detail), { fieldLabel: ((_a = detail.fieldLabels) === null || _a === void 0 ? void 0 : _a[language]) || detail.fieldName, displayOldValue: (_c = (_b = detail.displayOldValue) === null || _b === void 0 ? void 0 : _b[language]) !== null && _c !== void 0 ? _c : detail.oldValue, displayNewValue: (_e = (_d = detail.displayNewValue) === null || _d === void 0 ? void 0 : _d[language]) !== null && _e !== void 0 ? _e : detail.newValue }));
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* 获取操作标签(支持多语言)
|
|
1121
|
+
*/
|
|
1122
|
+
getOperationLabel(operation, language = 'zh') {
|
|
1123
|
+
var _a, _b;
|
|
1124
|
+
const labels = {
|
|
1125
|
+
CREATE: { zh: '创建', en: 'Create', ja: '作成' },
|
|
1126
|
+
UPDATE: { zh: '更新', en: 'Update', ja: '更新' },
|
|
1127
|
+
DELETE: { zh: '删除', en: 'Delete', ja: '削除' },
|
|
1128
|
+
RESTORE: { zh: '恢复', en: 'Restore', ja: '復元' },
|
|
1129
|
+
};
|
|
1130
|
+
return ((_a = labels[operation]) === null || _a === void 0 ? void 0 : _a[language]) || ((_b = labels[operation]) === null || _b === void 0 ? void 0 : _b.zh) || operation;
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* 分析字段变化(支持多语言)
|
|
1134
|
+
* @param oldValue 旧值
|
|
1135
|
+
* @param newValue 新值
|
|
1136
|
+
* @param operation 操作类型
|
|
1137
|
+
* @param entityClass 实体类(可选,用于获取字段和值的多语言标签)
|
|
1138
|
+
* @param language 语言(默认中文)
|
|
1139
|
+
*/
|
|
1140
|
+
analyzeFieldChanges(oldValue, newValue, operation, entityClass, language = 'zh') {
|
|
1141
|
+
const changes = [];
|
|
1142
|
+
const allFields = new Set([...Object.keys(oldValue), ...Object.keys(newValue)]);
|
|
1143
|
+
for (const field of allFields) {
|
|
1144
|
+
const oldVal = oldValue[field];
|
|
1145
|
+
const newVal = newValue[field];
|
|
1146
|
+
let changeType;
|
|
1147
|
+
if (operation === enums_1.AuditOperation.CREATE) {
|
|
1148
|
+
// 创建操作,所有字段都是新增
|
|
1149
|
+
changeType = 'added';
|
|
1150
|
+
}
|
|
1151
|
+
else if (operation === enums_1.AuditOperation.DELETE) {
|
|
1152
|
+
// 删除操作,所有字段都是移除
|
|
1153
|
+
changeType = 'removed';
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
// 更新操作,判断字段变化
|
|
1157
|
+
if (oldVal === undefined && newVal !== undefined) {
|
|
1158
|
+
changeType = 'added';
|
|
1159
|
+
}
|
|
1160
|
+
else if (oldVal !== undefined && newVal === undefined) {
|
|
1161
|
+
changeType = 'removed';
|
|
1162
|
+
}
|
|
1163
|
+
else if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
|
|
1164
|
+
changeType = 'modified';
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
changeType = 'unchanged';
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
// 跳过未变化的字段(对于UPDATE操作)
|
|
1171
|
+
if (changeType === 'unchanged' && operation === enums_1.AuditOperation.UPDATE) {
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
// 获取字段的多语言标签
|
|
1175
|
+
let fieldLabel = field;
|
|
1176
|
+
if (entityClass) {
|
|
1177
|
+
try {
|
|
1178
|
+
fieldLabel = (0, entity_audit_decorator_1.getFieldLabel)(entityClass, field, language);
|
|
1179
|
+
}
|
|
1180
|
+
catch (error) {
|
|
1181
|
+
// 忽略错误,使用原字段名
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
// 获取字段值的多语言标签
|
|
1185
|
+
let displayOldValue = this.formatDisplayValue(oldVal);
|
|
1186
|
+
let displayNewValue = this.formatDisplayValue(newVal);
|
|
1187
|
+
if (entityClass) {
|
|
1188
|
+
try {
|
|
1189
|
+
if (oldVal !== null && oldVal !== undefined) {
|
|
1190
|
+
const valueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, field, oldVal, language);
|
|
1191
|
+
if (valueLabel !== oldVal) {
|
|
1192
|
+
displayOldValue = valueLabel;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (newVal !== null && newVal !== undefined) {
|
|
1196
|
+
const valueLabel = (0, entity_audit_decorator_1.getFieldValueLabel)(entityClass, field, newVal, language);
|
|
1197
|
+
if (valueLabel !== newVal) {
|
|
1198
|
+
displayNewValue = valueLabel;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
catch (error) {
|
|
1203
|
+
// 忽略错误,使用默认格式化值
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
changes.push({
|
|
1207
|
+
field,
|
|
1208
|
+
fieldLabel,
|
|
1209
|
+
oldValue: oldVal,
|
|
1210
|
+
newValue: newVal,
|
|
1211
|
+
changeType,
|
|
1212
|
+
displayOldValue,
|
|
1213
|
+
displayNewValue,
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
return changes;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* 格式化显示值
|
|
1220
|
+
*/
|
|
1221
|
+
formatDisplayValue(value) {
|
|
1222
|
+
if (value === null || value === undefined) {
|
|
1223
|
+
return '';
|
|
1224
|
+
}
|
|
1225
|
+
if (typeof value === 'object') {
|
|
1226
|
+
return JSON.stringify(value);
|
|
1227
|
+
}
|
|
1228
|
+
return String(value);
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* 按字段分组统计
|
|
1232
|
+
*/
|
|
1233
|
+
groupBy(items, field) {
|
|
1234
|
+
return items.reduce((acc, item) => {
|
|
1235
|
+
const key = item[field];
|
|
1236
|
+
acc[key] = (acc[key] || 0) + 1;
|
|
1237
|
+
return acc;
|
|
1238
|
+
}, {});
|
|
1239
|
+
}
|
|
466
1240
|
};
|
|
467
1241
|
exports.EntityAuditService = EntityAuditService;
|
|
468
1242
|
exports.EntityAuditService = EntityAuditService = __decorate([
|
|
469
1243
|
(0, common_1.Injectable)(),
|
|
470
1244
|
__param(0, (0, typeorm_1.InjectRepository)(entities_1.EntityAuditLogEntity)),
|
|
471
1245
|
__param(1, (0, typeorm_1.InjectRepository)(entities_1.EntityTransactionEntity)),
|
|
472
|
-
__param(2, (0,
|
|
473
|
-
__param(
|
|
474
|
-
__param(5, (0, common_1.Inject)('AUDIT_STRATEGY')),
|
|
1246
|
+
__param(2, (0, typeorm_1.InjectRepository)(entities_1.ManualOperationLogEntity)),
|
|
1247
|
+
__param(3, (0, common_1.Inject)('AUDIT_ENTITY_MANAGER')),
|
|
475
1248
|
__param(6, (0, common_1.Optional)()),
|
|
476
|
-
__param(6, (0, common_1.Inject)('
|
|
1249
|
+
__param(6, (0, common_1.Inject)('AUDIT_STRATEGY')),
|
|
477
1250
|
__param(7, (0, common_1.Optional)()),
|
|
478
|
-
__param(7, (0, common_1.Inject)('
|
|
1251
|
+
__param(7, (0, common_1.Inject)('AUDIT_CONFIG')),
|
|
1252
|
+
__param(8, (0, common_1.Optional)()),
|
|
1253
|
+
__param(8, (0, common_1.Inject)('AUDIT_CONNECTION_NAME')),
|
|
1254
|
+
__param(9, (0, common_1.Optional)()),
|
|
1255
|
+
__param(9, (0, typeorm_1.InjectRepository)(entities_1.AuditActionSummaryEntity)),
|
|
1256
|
+
__param(10, (0, common_1.Optional)()),
|
|
479
1257
|
__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
1258
|
+
typeorm_2.Repository,
|
|
480
1259
|
typeorm_2.Repository,
|
|
481
1260
|
typeorm_2.EntityManager,
|
|
482
1261
|
audit_context_service_1.AuditContextService,
|
|
483
|
-
multi_database_service_1.MultiDatabaseService, Object, Object, String
|
|
1262
|
+
multi_database_service_1.MultiDatabaseService, Object, Object, String, typeorm_2.Repository,
|
|
1263
|
+
operation_description_service_1.OperationDescriptionService])
|
|
484
1264
|
], EntityAuditService);
|