From 75110de7892eb1d0d087a7ec918a20c6906a1831 Mon Sep 17 00:00:00 2001 From: colin Date: Tue, 30 May 2023 13:37:28 +0800 Subject: [PATCH] add entity-change manage --- aspnet-core/LINGYUN.MicroService.All.sln | 24 ++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ ....EntityChange.Application.Contracts.csproj | 27 ++++ ...pEntityChangeApplicationContractsModule.cs | 29 +++++ .../Abp/EntityChange/EntityChangeDto.cs | 26 ++++ .../EntityChange/EntityChangeGetListInput.cs | 14 +++ .../EntityChange/EntityPropertyChangeDto.cs | 15 +++ .../EntityChange/IEntityChangeAppService.cs | 10 ++ .../EntityChange/IEntityRestoreAppService.cs | 10 ++ .../Localization/AbpEntityChangeResource.cs | 8 ++ .../Localization/Resources/en.json | 12 ++ .../Localization/Resources/zh-Hans.json | 12 ++ .../Abp/EntityChange/RestoreEntitiesInput.cs | 10 ++ .../Abp/EntityChange/RestoreEntityInput.cs | 21 ++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ ...INGYUN.Abp.EntityChange.Application.csproj | 20 +++ .../AbpEntityChangeApplicationModule.cs | 23 ++++ .../AbpEntityChangeMapperProfile.cs | 13 ++ .../EntityChange/EntityChangeAppService.cs | 44 +++++++ .../EntityChange/EntityRestoreAppService.cs | 117 ++++++++++++++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ .../LINGYUN.Abp.EntityChange.HttpApi.csproj | 19 +++ .../AbpEntityChangeHttpApiModule.cs | 26 ++++ .../EntityChange/EntityChangeController.cs | 26 ++++ .../EntityChange/EntityRestoreController.cs | 32 +++++ 28 files changed, 637 insertions(+) create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xml create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xsd create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN.Abp.EntityChange.Application.Contracts.csproj create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationContractsModule.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeDto.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeGetListInput.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityPropertyChangeDto.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityChangeAppService.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityRestoreAppService.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/AbpEntityChangeResource.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/en.json create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/zh-Hans.json create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntitiesInput.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntityInput.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xml create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xsd create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN.Abp.EntityChange.Application.csproj create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationModule.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeMapperProfile.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityChangeAppService.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityRestoreAppService.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xml create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xsd create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN.Abp.EntityChange.HttpApi.csproj create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/AbpEntityChangeHttpApiModule.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityChangeController.cs create mode 100644 aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityRestoreController.cs diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index dc6fe1a73..88a92b028 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -633,6 +633,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Elsa.Notificati EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Elsa.Server", "modules\elsa\LINGYUN.Abp.Elsa.Server\LINGYUN.Abp.Elsa.Server.csproj", "{C465BB41-9DB7-470F-BC7F-A59D2A7D6083}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "entity-change", "entity-change", "{DD1B10ED-73E2-41BE-928A-46501050FE2A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.EntityChange.Application.Contracts", "modules\entity-change\LINGYUN.Abp.EntityChange.Application.Contracts\LINGYUN.Abp.EntityChange.Application.Contracts.csproj", "{7779D9BD-5928-49A2-965F-537967004238}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.EntityChange.Application", "modules\entity-change\LINGYUN.Abp.EntityChange.Application\LINGYUN.Abp.EntityChange.Application.csproj", "{AC41F335-E240-47E0-B409-AFAD1400E626}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.EntityChange.HttpApi", "modules\entity-change\LINGYUN.Abp.EntityChange.HttpApi\LINGYUN.Abp.EntityChange.HttpApi.csproj", "{1D420BA6-2155-4E0D-AAAF-EECC0330A38C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1623,6 +1631,18 @@ Global {C465BB41-9DB7-470F-BC7F-A59D2A7D6083}.Debug|Any CPU.Build.0 = Debug|Any CPU {C465BB41-9DB7-470F-BC7F-A59D2A7D6083}.Release|Any CPU.ActiveCfg = Release|Any CPU {C465BB41-9DB7-470F-BC7F-A59D2A7D6083}.Release|Any CPU.Build.0 = Release|Any CPU + {7779D9BD-5928-49A2-965F-537967004238}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7779D9BD-5928-49A2-965F-537967004238}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7779D9BD-5928-49A2-965F-537967004238}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7779D9BD-5928-49A2-965F-537967004238}.Release|Any CPU.Build.0 = Release|Any CPU + {AC41F335-E240-47E0-B409-AFAD1400E626}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC41F335-E240-47E0-B409-AFAD1400E626}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC41F335-E240-47E0-B409-AFAD1400E626}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC41F335-E240-47E0-B409-AFAD1400E626}.Release|Any CPU.Build.0 = Release|Any CPU + {1D420BA6-2155-4E0D-AAAF-EECC0330A38C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D420BA6-2155-4E0D-AAAF-EECC0330A38C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D420BA6-2155-4E0D-AAAF-EECC0330A38C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D420BA6-2155-4E0D-AAAF-EECC0330A38C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1929,6 +1949,10 @@ Global {10CF8240-4276-4199-B3D1-C45F16468EBD} = {0A00FAF9-A96B-4BF5-8D42-15C8678F70F3} {39DFEFCD-7C73-450F-9A2F-7426188A890B} = {0A00FAF9-A96B-4BF5-8D42-15C8678F70F3} {C465BB41-9DB7-470F-BC7F-A59D2A7D6083} = {0A00FAF9-A96B-4BF5-8D42-15C8678F70F3} + {DD1B10ED-73E2-41BE-928A-46501050FE2A} = {C5CAD011-DF84-4914-939C-0C029DCEF26F} + {7779D9BD-5928-49A2-965F-537967004238} = {DD1B10ED-73E2-41BE-928A-46501050FE2A} + {AC41F335-E240-47E0-B409-AFAD1400E626} = {DD1B10ED-73E2-41BE-928A-46501050FE2A} + {1D420BA6-2155-4E0D-AAAF-EECC0330A38C} = {DD1B10ED-73E2-41BE-928A-46501050FE2A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xml b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xsd b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN.Abp.EntityChange.Application.Contracts.csproj b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN.Abp.EntityChange.Application.Contracts.csproj new file mode 100644 index 000000000..dbf1533f8 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN.Abp.EntityChange.Application.Contracts.csproj @@ -0,0 +1,27 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationContractsModule.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationContractsModule.cs new file mode 100644 index 000000000..2cc681c24 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationContractsModule.cs @@ -0,0 +1,29 @@ +using LINGYUN.Abp.EntityChange.Localization; +using Volo.Abp.Application; +using Volo.Abp.Auditing; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.EntityChange; + +[DependsOn( + typeof(AbpAuditingModule), + typeof(AbpDddApplicationContractsModule))] +public class AbpEntityChangeApplicationContractsModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add() + .AddVirtualJson("/LINGYUN/Abp/EntityChange/Localization/Resources"); + }); + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeDto.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeDto.cs new file mode 100644 index 000000000..a5a29c20c --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeDto.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Auditing; + +namespace LINGYUN.Abp.EntityChange; + +public class EntityChangeDto : ExtensibleEntityDto +{ + public DateTime ChangeTime { get; set; } + + public EntityChangeType ChangeType { get; set; } + + public Guid? EntityTenantId { get; set; } + + public string EntityId { get; set; } + + public string EntityTypeFullName { get; set; } + + public List PropertyChanges { get; set; } + + public EntityChangeDto() + { + PropertyChanges = new List(); + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeGetListInput.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeGetListInput.cs new file mode 100644 index 000000000..ee9d9b5e5 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityChangeGetListInput.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Auditing; + +namespace LINGYUN.Abp.EntityChange; + +public class EntityChangeGetListInput : PagedAndSortedResultRequestDto +{ + public Guid? AuditLogId { get; set; } + public DateTime? StartTime { get; set; } + public DateTime? EndTime { get; set; } + public EntityChangeType? ChangeType { get; set; } + public string EntityId { get; set; } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityPropertyChangeDto.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityPropertyChangeDto.cs new file mode 100644 index 000000000..df56f8407 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/EntityPropertyChangeDto.cs @@ -0,0 +1,15 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.EntityChange; + +public class EntityPropertyChangeDto : EntityDto +{ + public string NewValue { get; set; } + + public string OriginalValue { get; set; } + + public string PropertyName { get; set; } + + public string PropertyTypeFullName { get; set; } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityChangeAppService.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityChangeAppService.cs new file mode 100644 index 000000000..d1129d49b --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityChangeAppService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.EntityChange; + +public interface IEntityChangeAppService : IApplicationService +{ + Task> GetListAsync(EntityChangeGetListInput input); +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityRestoreAppService.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityRestoreAppService.cs new file mode 100644 index 000000000..26ca2ed1e --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/IEntityRestoreAppService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.EntityChange; + +public interface IEntityRestoreAppService : IEntityChangeAppService +{ + Task RestoreEntityAsync(RestoreEntityInput input); + + Task RestoreEntitesAsync(RestoreEntitiesInput input); +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/AbpEntityChangeResource.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/AbpEntityChangeResource.cs new file mode 100644 index 000000000..582b52674 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/AbpEntityChangeResource.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.EntityChange.Localization; + +[LocalizationResourceName("AbpEntityChange")] +public class AbpEntityChangeResource +{ +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/en.json b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/en.json new file mode 100644 index 000000000..a62bd81ab --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/en.json @@ -0,0 +1,12 @@ +{ + "culture": "en", + "texts": { + "DisplayName:EntityId": "Entity Id", + "DisplayName:EntityChangeId": "Version", + "DisplayName:Entities": "Entities", + "DisplayName:AuditLogId": "Auditlog Id", + "DisplayName:StartTime": "Start Time", + "DisplayName:EndTime": "End Time", + "DisplayName:ChangeType": "Change Type" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/zh-Hans.json b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/zh-Hans.json new file mode 100644 index 000000000..25b92ce31 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/Localization/Resources/zh-Hans.json @@ -0,0 +1,12 @@ +{ + "culture": "zh-Hans", + "texts": { + "DisplayName:EntityId": "实体标识", + "DisplayName:EntityChangeId": "版本标识", + "DisplayName:Entities": "实体列表", + "DisplayName:AuditLogId": "审计标识", + "DisplayName:StartTime": "起始时间", + "DisplayName:EndTime": "截止时间", + "DisplayName:ChangeType": "变更类型" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntitiesInput.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntitiesInput.cs new file mode 100644 index 000000000..c9e1fd84d --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntitiesInput.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.EntityChange; + +public class RestoreEntitiesInput +{ + [Required] + public List Entities { get; set; } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntityInput.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntityInput.cs new file mode 100644 index 000000000..cb33d5b34 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application.Contracts/LINGYUN/Abp/EntityChange/RestoreEntityInput.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.Abp.EntityChange; + +public class RestoreEntityInput +{ + /// + /// 实体标识 + /// + [Required] + public string EntityId { get; set; } + /// + /// 还原到某个版本标识 + /// + /// + /// 注: 当传递此值时, 将还原到指定版本的NewValue + /// 否则,还原为最近一次版本的OriginalValue + /// + public Guid? EntityChangeId { get; set; } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xml b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xsd b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN.Abp.EntityChange.Application.csproj b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN.Abp.EntityChange.Application.csproj new file mode 100644 index 000000000..1d06b272c --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN.Abp.EntityChange.Application.csproj @@ -0,0 +1,20 @@ + + + + + + + net7.0 + + + + + + + + + + + + + diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationModule.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationModule.cs new file mode 100644 index 000000000..1922b0c47 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeApplicationModule.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Application; +using Volo.Abp.AutoMapper; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.EntityChange; + +[DependsOn( + typeof(AbpEntityChangeApplicationContractsModule), + typeof(AbpDddApplicationModule), + typeof(AbpAutoMapperModule))] +public class AbpEntityChangeApplicationModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeMapperProfile.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeMapperProfile.cs new file mode 100644 index 000000000..59d61ab95 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/AbpEntityChangeMapperProfile.cs @@ -0,0 +1,13 @@ +using AutoMapper; +using LINGYUN.Abp.AuditLogging; + +namespace LINGYUN.Abp.EntityChange; +public class AbpEntityChangeMapperProfile : Profile +{ + public AbpEntityChangeMapperProfile() + { + CreateMap(); + CreateMap() + .MapExtraProperties(); + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityChangeAppService.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityChangeAppService.cs new file mode 100644 index 000000000..fa6037fd1 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityChangeAppService.cs @@ -0,0 +1,44 @@ +using LINGYUN.Abp.AuditLogging; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.EntityChange; + +public abstract class EntityChangeAppService : ApplicationService, IEntityChangeAppService + where TEntity : class +{ + protected virtual string GetListPolicy { get; set; } + + protected IEntityChangeStore EntityChangeStore { get; } + + protected EntityChangeAppService(IEntityChangeStore entityChangeStore) + { + EntityChangeStore = entityChangeStore; + } + + public async virtual Task> GetListAsync(EntityChangeGetListInput input) + { + if (!GetListPolicy.IsNullOrWhiteSpace()) + { + await AuthorizationService.AuthorizeAsync(GetListPolicy); + } + + var entityTypeFullName = typeof(TEntity).FullName; + + var totalCount = await EntityChangeStore.GetCountAsync( + input.AuditLogId, input.StartTime, input.EndTime, + input.ChangeType, input.EntityId, entityTypeFullName); + + var entities = await EntityChangeStore.GetListAsync( + input.Sorting, input.MaxResultCount, input.SkipCount, + input.AuditLogId, input.StartTime, input.EndTime, + input.ChangeType, input.EntityId, entityTypeFullName); + + return new PagedResultDto(totalCount, + ObjectMapper.Map, List>(entities)); + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityRestoreAppService.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityRestoreAppService.cs new file mode 100644 index 000000000..416888d38 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.Application/LINGYUN/Abp/EntityChange/EntityRestoreAppService.cs @@ -0,0 +1,117 @@ +using LINGYUN.Abp.AuditLogging; +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Json; +using Volo.Abp.Reflection; + +namespace LINGYUN.Abp.EntityChange; + +public abstract class EntityRestoreAppService : EntityChangeAppService, IEntityRestoreAppService + where TEntity : class, IEntity +{ + protected virtual string RestorePolicy { get; set; } + + protected IRepository Repository { get; } + + protected IJsonSerializer JsonSerializer => LazyServiceProvider.LazyGetRequiredService(); + + protected EntityRestoreAppService( + IEntityChangeStore entityChangeStore, + IRepository repository) + : base(entityChangeStore) + { + Repository = repository; + } + + public async virtual Task RestoreEntitesAsync(RestoreEntitiesInput input) + { + if (!RestorePolicy.IsNullOrWhiteSpace()) + { + await AuthorizationService.AuthorizeAsync(RestorePolicy); + } + + foreach (var restoreEntity in input.Entities) + { + await RestoreEntityByAuditLogAsync(restoreEntity); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + public async virtual Task RestoreEntityAsync(RestoreEntityInput input) + { + if (!RestorePolicy.IsNullOrWhiteSpace()) + { + await AuthorizationService.AuthorizeAsync(RestorePolicy); + } + + await RestoreEntityByAuditLogAsync(input); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + protected virtual TKey MapToEntityKey(string entityId) + { + return (TKey)Convert.ChangeType(entityId, typeof(TKey)); + } + + protected async virtual Task RestoreEntityByAuditLogAsync(RestoreEntityInput input) + { + var entityChanges = await EntityChangeStore.GetListAsync( + entityId: input.EntityId, + entityTypeFullName: typeof(TEntity).FullName); + var entityKey = MapToEntityKey(input.EntityId); + + if (entityChanges != null && entityChanges.Any()) + { + var entity = await Repository.GetAsync(entityKey); + var entityProperties = typeof(TEntity).GetProperties(); + var entityChange = entityChanges + .WhereIf(input.EntityChangeId.HasValue, x => x.Id == input.EntityChangeId) + .OrderByDescending(x => x.ChangeTime) + .First(); + + foreach (var propertyChange in entityChange.PropertyChanges) + { + var propertyName = propertyChange.PropertyName; + var entityProperty = entityProperties.FirstOrDefault(x => x.Name == propertyName && x.GetSetMethod(true) != null); + if (entityProperty != null) + { + if (TypeHelper.IsPrimitiveExtended(entityProperty.PropertyType, includeEnums: true)) + { + var conversionType = entityProperty.PropertyType; + var isNullableType = TypeHelper.IsNullable(conversionType); + if (isNullableType) + { + conversionType = conversionType.GetFirstGenericArgumentIfNullable(); + } + + var currentValue = propertyChange.OriginalValue; + if (input.EntityChangeId.HasValue) + { + currentValue = propertyChange.NewValue; + } + if (currentValue.IsNullOrWhiteSpace() || string.Equals("null", currentValue, StringComparison.InvariantCultureIgnoreCase)) + { + if (isNullableType) + { + entityProperty.SetValue(entity, null); + } + continue; + } + + var setPropertyValue = JsonSerializer.Deserialize(conversionType, currentValue); + entityProperty.SetValue(entity, setPropertyValue); + } + } + } + + await Repository.UpdateAsync(entity); + } + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xml b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xsd b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN.Abp.EntityChange.HttpApi.csproj b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN.Abp.EntityChange.HttpApi.csproj new file mode 100644 index 000000000..88bd530f6 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN.Abp.EntityChange.HttpApi.csproj @@ -0,0 +1,19 @@ + + + + + + + net7.0 + + + + + + + + + + + + diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/AbpEntityChangeHttpApiModule.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/AbpEntityChangeHttpApiModule.cs new file mode 100644 index 000000000..7647bde95 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/AbpEntityChangeHttpApiModule.cs @@ -0,0 +1,26 @@ +using LINGYUN.Abp.EntityChange.Localization; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.EntityChange; + +[DependsOn( + typeof(AbpEntityChangeApplicationContractsModule), + typeof(AbpAspNetCoreMvcModule))] +public class AbpEntityChangeHttpApiModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpEntityChangeHttpApiModule).Assembly); + }); + + PreConfigure(options => + { + options.AddAssemblyResource(typeof(AbpEntityChangeResource), typeof(AbpEntityChangeApplicationContractsModule).Assembly); + }); + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityChangeController.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityChangeController.cs new file mode 100644 index 000000000..132d020c9 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityChangeController.cs @@ -0,0 +1,26 @@ +using LINGYUN.Abp.EntityChange.Localization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.EntityChange; + +public abstract class EntityChangeController : AbpControllerBase, IEntityChangeAppService +{ + protected IEntityChangeAppService EntityChangeAppService { get; } + + protected EntityChangeController(IEntityChangeAppService entityChangeAppService) + { + EntityChangeAppService = entityChangeAppService; + + LocalizationResource = typeof(AbpEntityChangeResource); + } + + [HttpGet] + [Route("entity-changes")] + public virtual Task> GetListAsync(EntityChangeGetListInput input) + { + return EntityChangeAppService.GetListAsync(input); + } +} diff --git a/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityRestoreController.cs b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityRestoreController.cs new file mode 100644 index 000000000..93f65c6b4 --- /dev/null +++ b/aspnet-core/modules/entity-change/LINGYUN.Abp.EntityChange.HttpApi/LINGYUN/Abp/EntityChange/EntityRestoreController.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.EntityChange; + +public abstract class EntityRestoreController : EntityChangeController, IEntityRestoreAppService +{ + protected IEntityRestoreAppService EntityRestoreAppService { get; } + + protected EntityRestoreController(IEntityRestoreAppService entityRestoreAppService) + + : base(entityRestoreAppService) + { + EntityRestoreAppService = entityRestoreAppService; + } + + [HttpPut] + [Route("entites-restore")] + public virtual Task RestoreEntitesAsync(RestoreEntitiesInput input) + { + return EntityRestoreAppService.RestoreEntitesAsync(input); + } + + [HttpPut] + [Route("entity-restore")] + [Route("{EntityId}/entity-restore")] + [Route("{EntityId}/v/{EntityChangeId}/entity-restore")] + public virtual Task RestoreEntityAsync(RestoreEntityInput input) + { + return EntityRestoreAppService.RestoreEntityAsync(input); + } +}